Термин агрегации вложенных объектов со смешанным вложенным/невложенным фильтром

У нас есть аспекты, показывающие количество результатов, которые будут отображаться при выборе фильтров (и их объединении). Что-то вроде этого:

Пример фильтров

До того, как мы представили вложенные объекты, для этого подошло бы следующее:

GET /x_v1/_search/
{
  "size": 0,
  "aggs": {
    "FilteredDescriptiveFeatures": {
      "filter": {
        "bool": {
          "must": [
            {
              "terms": {
                "breadcrumbs.categoryIds": [
                  "category"
                ]
              }
            },
            {
              "terms": {
                "products.sterile": [
                  "0"
                ]
              }
            }
          ]
        }
      },
      "aggs": {
        "DescriptiveFeatures": {
          "terms": {
            "field": "products.descriptiveFeatures",
            "size": 1000
          }
        }
      }
    }
  }
}

Это дает результат:

  "aggregations": {
    "FilteredDescriptiveFeatures": {
      "doc_count": 280,
      "DescriptiveFeatures": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": "somekey",
            "doc_count": 42
          },

Однако нам нужно было сделать products вложенным объектом, и в настоящее время я пытаюсь переписать приведенное выше, чтобы оно работало с этим изменением. Моя попытка выглядит следующим образом. Однако это не дает правильного результата и, похоже, неправильно подключено к фильтру.

GET /x_v2/_search/
{
  "size": 0,
  "aggs": {
    "FilteredDescriptiveFeatures": {
      "filter": {
        "bool": {
          "must": [
            {
              "terms": {
                "breadcrumbs.categoryIds": [
                  "category"
                ]
              }
            },
            {
              "nested": {
                "path": "products",
                "query": {
                  "terms": {
                    "products.sterile": [
                      "0"
                    ]
                  }
                }
              }
            }
          ]
        }
      },
      "aggs": {
        "nested": {
          "nested": {
            "path": "products"
          },
          "aggregations": {
            "DescriptiveFeatures": {
              "terms": {
                "field": "products.descriptiveFeatures",
                "size": 1000
              }
            }
          }
        }
      }
    }
  }
}

Это дает результат:

  "aggregations": {
    "FilteredDescriptiveFeatures": {
      "doc_count": 280,
      "nested": {
        "doc_count": 1437,
        "DescriptiveFeatures": {
          "doc_count_error_upper_bound": 0,
          "sum_other_doc_count": 0,
          "buckets": [
            {
              "key": "somekey",
              "doc_count": 164
            },

Я также попытался поместить вложенное определение выше, чтобы оно содержало как фильтр, так и агги, но тогда термин фильтра хлебные крошки.categoryId, которого нет во вложенном объекте, не будет работать.

Возможно ли то, что я пытаюсь сделать? И как это можно решить?


person user3533716    schedule 30.08.2019    source источник


Ответы (2)


На шаге FilteredDescriptiveFeatures вы возвращаете все документы, содержащие один продукт, с sterile = 0

Но после того, как в nested step вы не указываете снова этот фильтр. Таким образом, на этом шаге возвращаются все вложенные продукты, таким образом, вы выполняете агрегацию условий для всех продуктов, а не только для продуктов с sterile = 0.

Вы должны переместить свой стерильный фильтр на вложенный шаг. И, как указывает Рича, вам нужно использовать reverse_nested на последнем шаге для подсчета документа elasticsearch и не вложенных поддокументов продуктов.

Не могли бы вы попробовать этот запрос?

{
    "size": 0,
    "aggs": {
        "filteredCategory": {
            "filter": {
                "terms": {
                    "breadcrumbs.categoryIds": [
                        "category"
                    ]
                }
            },
            "aggs": {
                "nestedProducts": {
                    "nested": {
                        "path": "products"
                    },
                    "aggs": {
                        "filteredByProductsAttributes": {
                            "filter": {
                                "terms": {
                                    "products.sterile": [
                                        "0"
                                    ]
                                }
                            },
                            "aggs": {
                                "DescriptiveFeatures": {
                                    "terms": {
                                        "field": "products.descriptiveFeatures",
                                        "size": 1000
                                    },
                                    "aggs": {
                                        "productCount": {
                                            "reverse_nested": {}
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
person Pierre Mallet    schedule 30.08.2019

Из описания я понимаю, что вы хотите отфильтровать свои результаты на основе некоторых вложенных и невложенных полей, а затем применить агрегирование к вложенному полю. Я создал образец индекса и данных с некоторыми вложенными и невложенными полями и создал запрос

Сопоставление

    PUT stack-557722203
    {
      "mappings": {
        "_doc": {
          "properties": {
            "category": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "user": {
              "type": "nested",       // NESTED FIELD
              "properties": {
                "fName": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                },
                "lName": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                },
                "type": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                }
              }
            }
          }
        }
      }
    }

Пример данных

    POST _bulk
    {"index":{"_index":"stack-557722203","_id":"1","_type":"_doc"}}
    {"category":"X","user":[{"fName":"A","lName":"B","type":"X"},{"fName":"A","lName":"C","type":"X"},{"fName":"P","lName":"B","type":"Y"}]}
    {"index":{"_index":"stack-557722203","_id":"2","_type":"_doc"}}
    {"category":"X","user":[{"fName":"P","lName":"C","type":"Z"}]}
    {"index":{"_index":"stack-557722203","_id":"3","_type":"_doc"}}
    {"category":"X","user":[{"fName":"A","lName":"C","type":"Y"}]}
    {"index":{"_index":"stack-557722203","_id":"4","_type":"_doc"}}
    {"category":"Y","user":[{"fName":"A","lName":"C","type":"Y"}]}

Запрос

GET stack-557722203/_search
{
   "size": 0, 
   "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "user",
            "query": {
              "term": {
                "user.fName.keyword": {
                  "value": "A"
                }
              }
            }
          }
        },
        {
          "term": {
            "category.keyword": {
              "value": "X"
            }
          }
        }
      ]
    }
  },

  "aggs": {
    "group BylName": {
      "nested": {
        "path": "user"
      },
      "aggs": {
        "group By lName": {
         "terms": {
           "field": "user.lName.keyword",
           "size": 10
         },
         "aggs": {
           "reverse Nested": {
             "reverse_nested": {}    // NOTE THIS
           }
         }
        }
      }
    }
  }
}

Вывод

{
  "took": 18,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "group BylName": {
      "doc_count": 4,
      "group By lName": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": "B",
            "doc_count": 2,
            "reverse Nested": {
              "doc_count": 1
            }
          },
          {
            "key": "C",
            "doc_count": 2,
            "reverse Nested": {
              "doc_count": 2
            }
          }
        ]
      }
    }
  }
}

Согласно расхождению в данных, которые вы получаете, больше документов в doc_count, когда вы изменили сопоставление на Nested, связано с тем, как хранятся документы Nested и Object(NonNested). См. здесь, чтобы понять, как они хранятся внутри. Чтобы связать их обратно с корневым документом, вы можете использовать Обратное вложенное агрегирование, и тогда вы получите тот же результат.

Надеюсь это поможет!!

person Richa    schedule 30.08.2019
comment
Я думаю, что проблема не только в том, что он не использует обратную вложенность для точного подсчета документов. Также неуместен фильтр стерильность = 0. Его следует использовать в отфильтрованной агрегации под вложенной агрегацией. - person Pierre Mallet; 30.08.2019
comment
@PierreMallet Я думаю, что это невозможно, потому что если у вас есть вложенная агрегация сверху, вы не сможете использовать внутри нее невложенные поля. Вот почему я бы выбрал вложенный запрос выше агрегации, таким образом вы также получите преимущество, заключающееся в том, что вы получите только отфильтрованные документы, а затем агрегация будет применяться только к ним. Пожалуйста, поправьте меня, если есть некоторая путаница - person Richa; 30.08.2019
comment
если вы не добавите фильтр во вложенную агрегацию, агрегации будут применяться ко всем вложенным документам основного документа. @Richa, вы можете проверить мой ответ ниже, у меня нет времени его проверять, но он должен работать. У вас может быть несколько шагов фильтрации, по одному для каждого уровня вложенности. И это конец reverse_nested для подсчета документов, как вы выделили - person Pierre Mallet; 30.08.2019
comment
К сожалению, это не дает правильного результата (ответ Пьера Малле дает), но спасибо за указатели и особенно за то, что познакомили меня с обратной вложенной агрегацией. - person user3533716; 03.09.2019