ES - подпакеты, основанные на значениях в свойстве, а не на значениях документа - PullRequest
0 голосов
/ 13 ноября 2018

Я новичок в ElasticSearch и пытаюсь объединить объекты, полученные в результате поиска, по иерархическим категориям.

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

Что я пытаюсь достичь

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

Вот упрощенное отображение документа, который содержит только минимальные данные:

{
  "mappings": {
    "_doc": {
      "properties": {
        "categoriesList": {
          "properties": {
            "depth": {
              "type": "long"
            },
            "title": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        }
      }
    }
  }
}

Вот упрощенный образец документа:

{
  "_index": "x",
  "_type": "_doc",
  "_id": "wY0w5GYBOIOl7fi31c_b",
  "_score": 22.72073,
  "_source": {
    "categoriesList": [
      {
        "title": "category_lvl_2_2",
        "depth": 2
      },
      {
        "title": "category_lvl_2",
        "depth": 2,
      },
      {
        "title": "category_lvl_1",
        "depth": 1
      }
    ]
  }
}

Теперь я пытаюсь получить иерархические сегменты категорий на основе их глубины, т. Е. Я хочу иметь блок, содержащий все заголовки категорий глубины 1 по всем попаданиям, а затем другой блок (или вложенный сегмент) с названиями только категорий глубины 2 для всех хитов и так далее. Что-то вроде:

"aggregations": {
    "depth": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 1,
          "doc_count": 47,
          "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "category_lvl_1",
                "doc_count": 47,
                "depth_1": {
                  "doc_count": 47
                }
              }
            ]
          }
        },
        {
          "key": 2,
          "doc_count": 47,
          "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "category_lvl_2_1",
                "doc_count": 47
              },
              {
                "key": "category_lvl_2_2",
                "doc_count": 33
              }
            ]
          }
        }
      ]
    }
  }

Что я пробовал

Сначала я попытался просто создать вложенные агрегаты следующим образом:

  "aggs": {
    "depth": {
      "terms": {
        "field": "categoriesList.depth"
      },
      "aggs": {
        "name": {
          "terms": {
            "field": "categoriesList.title.keyword"
          },
        }
      }
    }
  }

Это, конечно, не дало то, что я хотел. Это в основном дало мне ведра, ключи которых были по глубине, но в них были все названия всех категорий, независимо от их глубины; содержимое было одинаковым. Примерно так:

  "aggregations": {
    "depth": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 1,
          "doc_count": 47,
          "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "category_lvl_1",
                "doc_count": 47
              },
              {
                "key": "category_lvl_2_1",
                "doc_count": 33
              },
              {
                "key": "category_lvl_2_2",
                "doc_count": 15
              }
            ]
          }
        },
        {
          "key": 2,
          "doc_count": 47,
          "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "category_lvl_1",
                "doc_count": 47
              },
              {
                "key": "category_lvl_2_1",
                "doc_count": 33
              },
              {
                "key": "category_lvl_2_2",
                "doc_count": 15
              }
            ]
          }
        }
      ]
    }
  }

Затем я попытался посмотреть, сработает ли отфильтрованная агрегация, попытавшись отфильтровать одно вложенное ведро по значению глубины 1:

  "aggs": {
    "depth": {
      "terms": {
        "field": "categoriesList.depth"
      },
      "aggs": {
        "name": {
          "terms": {
            "field": "categoriesList.title.keyword"
          },
          "aggs": {
            "depth_1": {
              "filter": {
                "term": {
                  "categoriesList.depth": 1
                }
              }
            }
          }
        }
      }
    }
  }

Это дало те же результаты, что и простой запрос агрегации выше, но с дополнительным уровнем вложенности, который не имел смысла.

Вопрос

С моим текущим пониманием ES, то, что я вижу, имеет смысл: оно просматривает каждый документ из поиска и затем создает сегменты на основе глубины категории, но, поскольку каждый документ имеет по крайней мере одну категорию с каждой глубиной, весь список категорий добавлен в корзину.

Возможно ли то, что я пытаюсь сделать с помощью ES? У меня такое ощущение, что это не сработает, потому что я в основном пытаюсь создать и отфильтровать свойства, использованные в исходном запросе, а не работать со свойствами документа.

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

Спасибо!

1 Ответ

0 голосов
/ 15 ноября 2018

Основываясь на комментарии sramalingam24 , я сделал следующее, чтобы оно заработало:

Создание индекса с отображением с указанием вложенных типов

Я изменил отображение, чтобы сообщить ES, что свойство categoryList является вложенным объектом. Для этого я создал новый индекс со следующим отображением:

{
  "mappings": {
    "_doc": {
      "properties": {
        "categoriesList": {
          "type": "nested",
          "properties": {
            "depth": {
              "type": "long"
            },
            "title": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        }
      }
    }
  }
}

Переиндексировать в новый индекс

Затем я переиндексирую старый индекс в новый.

{
  "source": {
    "index": "old_index"
  },
  "dest": {
    "index": "index_with_nested_mapping"
  }
}

Использовать вложенную агрегацию

Затем я использовал вложенную агрегацию, подобную этой:

{
  "aggs": {
    "categories": {
      "nested": {
        "path": "categoriesList"
      },
      "aggs": {
        "depth": {
          "terms": {
            "field": "categoriesList.depth"
          },
          "aggs": {
            "sub-categories": {
              "terms": {
                "field": "categoriesList.title.keyword"
              }
            }
          }
        }
      }
    }
  }
}

Что дало мне желаемый результат:

{
  "aggregations": {
    "categories": {
      "doc_count": 96,
      "depth": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": 2,
            "doc_count": 49,
            "sub-categories": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "category_lvl_2_1",
                  "doc_count": 33
                },
                {
                  "key": "category_lvl_2_2",
                  "doc_count": 15
                }
              ]
            }
          },
          {
            "key": 1,
            "doc_count": 47,
            "sub-categories": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "category_lvl_1",
                  "doc_count": 47
                }
              ]
            }
          }
        ]
      }
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...