Агрегация Elasticsearch с иерархической категорией, подкатегорией;ограничить уровни - PullRequest
0 голосов
/ 23 октября 2018

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

например, у меня есть такие фасеты, как:

auto, tools & travel    (115)
auto, tools & travel > luggage tags (90)
auto, tools & travel > luggage tags > luggage spotters  (40)
auto, tools & travel > luggage tags > something else    (50)
auto, tools & travel > car organizers   (25)

При использовании агрегации, например

"aggs": {
    "cat_groups": {
      "terms": {
        "field": "categories.keyword",
        "size": 10,
       "include": "auto, tools & travel > .*"
      }
    }
}

Я получаю сегменты типа

"buckets": [
        {
          "auto, tools & travel > luggage tags",
          "doc_count": 90
        },
        {
          "key": "auto, tools & travel > luggage tags > luggage spotters",
          "doc_count": 40
        },
        {
          "key": "auto, tools & travel > luggage tags > something else",
          "doc_count": 50
        },
        {
          "key": "auto, tools & travel > car organizers",
          "doc_count": 25
        }
]

Но я хочу ограничить уровень.например, я хочу получить только результаты для auto, tools & travel > luggage tags.Как я могу ограничить уровни?Кстати, "exclude": ".* > .* > .*" у меня не работает.

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

Elasticsearch версия 6.4

Ответы [ 2 ]

0 голосов
/ 28 января 2019

Просто добавьте целочисленное поле с именем level, обозначающее уровень вашей категории в иерархии.Просто посчитайте количество вхождений вашего разделителя '>' и сохраните его как значение.Затем добавьте rangeQuery к вашему boolQuery.

Добавьте это к вашей схеме:

"level": {
    "type": "integer",
    "store": "true",
    "index": "true"
}

В вашем коде есть что-то вроде этого, которое подсчитывает количество разделителей, указывающих уровень иерархии (нетразделитель означает основную категорию):

public Builder(final String path) {
    this.path = path;
    this.level = StringUtils.countMatches(path, DELIMITER);
}

, и тогда в вашем поисковом запросе может быть что-то вроде:

{
    "query": {
        "bool": {
            "filter": [
                {
                    "prefix": {
                        "category": {
                            "value": "auto, tools & travel",
                            "boost": 1
                        }
                    }
                },
                {
                    "range": {
                        "level": {
                            "from": 2,
                            "to": 4,
                            "include_lower": true,
                            "include_upper": true,
                            "boost": 1
                        }
                    }
                }
            ],
            "adjust_pure_negative": true,
            "boost": 1
        }
    }
}
0 голосов
/ 23 октября 2018

Наконец-то я смог понять приведенную ниже технику.

Я реализовал custom analyzer с использованием Токенайзер Иерархии пути , и я создал мультиполе с именем categories, чтобы вы могли использовать categories.facets для агрегатов / фасетов и делать обычный текстпоиск с использованием categories.

Пользовательский анализатор будет применяться только для categories.facets

Обратите внимание на свойство "fielddata": "true" для моего поля categories.facet

Mapping

PUT myindex
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "path_hierarchy",
          "delimiter": ">"
        }
      }
    }
  },
  "mappings": {
    "mydocs": {
      "properties": {
        "categories": {
          "type": "text",
          "fields": {
            "facet": { 
              "type":  "text",
              "analyzer": "my_analyzer",
              "fielddata": "true"
            }
          }
        }
      }
    }
  }
}

Образцы документов

POST myindex/mydocs/1
{
    "categories" : "auto, tools & travel > luggage tags > luggage spotters"
}

POST myindex/mydocs/2
{
    "categories" : "auto, tools & travel > luggage tags > luggage spotters"
}

POST myindex/mydocs/3
{
    "categories" : "auto, tools & travel > luggage tags > luggage spotters"
}

POST myindex/mydocs/4
{
    "categories" : "auto, tools & travel > luggage tags > something else"
}

Запрос

Вы можете попробовать следующий запрос, который вы ищете.Я снова применил Фильтр агрегации , потому что вам нужны только конкретные слова вместе с Термины агрегации .

{
  "size": 0,
  "aggs":{
    "facets": {
      "filter": { 
          "bool": {
            "must": [
              { "match": { "categories": "luggage"} }
            ]
         }
      },
      "aggs": {
        "categories": {
          "terms": {
            "field": "categories.facet"
          }
        }
      }
    }
  }
}

Ответ

{
    "took": 43,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 11,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "facets": {
            "doc_count": 4,
            "categories": {
                "doc_count_error_upper_bound": 0,
                "sum_other_doc_count": 0,
                "buckets": [
                    {
                        "key": "auto, tools & travel ",
                        "doc_count": 4
                    },
                    {
                        "key": "auto, tools & travel > luggage tags ",
                        "doc_count": 4
                    },
                    {
                        "key": "auto, tools & travel > luggage tags > luggage spotters",
                        "doc_count": 3
                    },
                    {
                        "key": "auto, tools & travel > luggage tags > something else",
                        "doc_count": 1
                    }
                ]
            }
        }
    }
}

Окончательный ответ Опубликовать в чате

POST myindex/_search
{
  "size": 0,
  "aggs":{
    "facets": {
      "filter": { 
          "bool": {
            "must": [
              { "match": { "categories": "luggage"} }
          ]
        }
      },
      "aggs": {
        "categories": {
          "terms": {
            "field": "categories.facet",
            "exclude": ".*>{1}.*>{1}.*"
          }
        }
      }
    }
  }
}

Обратите внимание, что я добавил exclude с regular expression в такомспособ, которым он не будет учитывать какие-либо аспекты, имеющие более одного вхождения >

Дайте мне знать, если это поможет.

...