Эластичный поиск - фильтр агрегации для вариантов продукта

У меня есть каталог продуктов, в котором каждый продукт проиндексирован следующим образом (запрашивается из http://localhost:9200/products/_doc/1) в качестве образца:

{
  "_index": "products_20201202145032789",
  "_type": "_doc",
  "_id": "1",
  "_version": 1,
  "_seq_no": 0,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "title": "Roncato Eglo",
    "description": "Amazing LED light made of wood and description continues.",
    "price": 3990,
    "manufacturer": "Eglo",
    "category": [
      "Lights",
      "Indoor lights"
    ],
    "options": [
      {
        "title": "Mount type",
        "value": "E27"
      },
      {
        "title": "Number of bulps",
        "value": "4"
      },
      {
        "title": "Batteries included",
        "value": "true"
      },
      {
        "title": "Ligt temperature",
        "value": "warm"
      },
      {
        "title": "Material",
        "value": "wood"
      },
      {
        "title": "Voltage",
        "value": "230"
      }
    ]
  }
}

Каждый параметр содержит разные значения, поэтому существует множество значений типа крепления, значений температуры света, значений материалов и т. Д.

Как я могу создать агрегацию (фильтр), где я могу позволить клиентам выбирать между различными вариантами Тип крепления:

[ ] E27
[X] E14
[X] GU10
...

Или позвольте им выбрать один из различных вариантов материала, отображаемых в виде флажков:

[X] Wood
[ ] Metal
[ ] Glass
...

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

Я успешно создал, отобразил и использую агрегаты для Категории, Производителя и других основных. Эти параметры продукта хранятся в has_many_through отношениях в базе данных. Я использую гем Rails + searchkick, но они позволяют мне создавать необработанные запросы для эластичного поиска.


person Lubomir Herko    schedule 02.12.2020    source источник


Ответы (1)


Предпосылкой для такой агрегации является наличие поля options как nested.

Пример сопоставления индекса:

PUT test
{
  "mappings": {
    "properties": {
      "title": {
        "type": "keyword"
      },
      "options": {
        "type": "nested",
        "properties": {
          "title": {
            "type": "keyword"
          },
          "value": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

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

PUT test/_doc/1
{
  "title": "Roncato Eglo",
  "options": [
    {
      "title": "Mount type",
      "value": "E27"
    },
    {
      "title": "Material",
      "value": "wood"
    }
  ]
}

PUT test/_doc/2
{
  "title": "Eglo",
  "options": [
    {
      "title": "Mount type",
      "value": "E27"
    },
    {
      "title": "Material",
      "value": "metal"
    }
  ]
}

Предположение: для данного документа title под option появляется только один раз. Например, может существовать только один вложенный документ под option, имеющий title как Material.

Запрос на агрегирование:

GET test/_search
{
  "size": 0, 
  "aggs": {
    "OPTION": {
      "nested": {
        "path": "options"
      },
      "aggs": {
        "TITLE": {
          "terms": {
            "field": "options.title",
            "size": 10
          },
          "aggs": {
            "VALUES": {
              "terms": {
                "field": "options.value",
                "size": 10
              }
            }
          }
        }
      }
    }
  }
}

Ответ:

{
  "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" : {
    "OPTION" : {
      "doc_count" : 4,
      "TITLE" : {
        "doc_count_error_upper_bound" : 0,
        "sum_other_doc_count" : 0,
        "buckets" : [
          {
            "key" : "Material",
            "doc_count" : 2,
            "VALUES" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "metal",
                  "doc_count" : 1
                },
                {
                  "key" : "wood",
                  "doc_count" : 1
                }
              ]
            }
          },
          {
            "key" : "Mount type",
            "doc_count" : 2,
            "VALUES" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "E27",
                  "doc_count" : 2
                }
              ]
            }
          }
        ]
      }
    }
  }
}
person Nishant    schedule 02.12.2020
comment
Большое спасибо! - person Lubomir Herko; 03.12.2020