Индексация каталога товаров в ElasticSearch и фасетный поиск.

Темы, не касающиеся фреймворка, но относящиеся к программированию в целом.
Ответить
chesar
Сообщения: 514
Зарегистрирован: 2013.04.10, 17:49

Индексация каталога товаров в ElasticSearch и фасетный поиск.

Сообщение chesar »

Разбираюсь с ES и хотелось бы попутно задать здесь вопросы возникающие в процессе ознакомления.
В MySql сейчас примерно такая схема:

Разделы товаров

Код: Выделить всё

CREATE TABLE `section` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR (255),
  `slug` VARCHAR (255)
)
Типы товаров

Код: Выделить всё

CREATE TABLE `type` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR (255),
  `slug` VARCHAR (255)
)
Товары

Код: Выделить всё

CREATE TABLE `product` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR (255),
  `aritcul` VARCHAR (255),
  `price` INT,
  `content` TEXT
);
Параметры

Код: Выделить всё

CREATE TABLE `product_param_name` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `parent` INT UNSIGNED NOT NULL,
  `name` VARCHAR (255),
  `key` VARCHAR (255),
  `` SMALLINT NOT NULL DEFAULT 0,
  `type` TEXT
);
Варианты значений параметра

Код: Выделить всё

CREATE TABLE `product_param_variant` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `param_id` INT UNSIGNED NOT NULL,
  `name` text NOT NULL
)
И привязки вариантов к продуктам

Код: Выделить всё

CREATE TABLE `product_param` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `param_id` INT UNSIGNED NOT NULL,
  `product_id` INT UNSIGNED NOT NULL,
  `variant_id` INT UNSIGNED NOT NULL,
  `value` text
);
Хочу проиндексировать каталог товаров, чтобы потом можно было строить фасетные фильтры. Первое что нужно понять - как денормализовать товар.
Первая мысль:

Код: Выделить всё

{
      "id": 6374,
      "articul": "so6374bc",
      "name": "X MUI 7z BLACK (2017/ 16')",
      "section": 7,
      "type": 6,

      "parameters": [
        {
          "name": "size",
          "value": ["9.5", "11"]
        },
        {
          "name": "color",
          "value": "22"
        },
        {
          "name": "gender",
          "value": "men"
        },
        {
          "name": "year",
          "value": "2017"
        }
      ]      
    }
Но это помоему это какая-то дичь. Наверно так правильней вот так:

Код: Выделить всё

{
  "id": 6374,
  "articul": "so6374bc",
  "name": "X MUI 7z BLACK (2017/ 16')",
  "section": 7,
  "type": 6,

  "parameters": {
    "size": ["9.5", "11"],
    "color": "22",
    "gender": "men",
    "year": "2017"
  }
}
?

Или вообще параметры не выносить в отдельное свойство и представлять их как обычные аттрибуты товара?
В админке у параметров есть чекбокс, определяющий использовать ли параметр в качестве фильтра на сайте, соответственно схема товара часто изменяется.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Индексация каталога товаров в ElasticSearch и фасетный поиск.

Сообщение ElisDN »

chesar писал(а): 2017.08.03, 12:55 Но это помоему это какая-то дичь.
Не дичь. Так и оставьте. Просто в маппинге обозначте типом 'nested'.
chesar
Сообщения: 514
Зарегистрирован: 2013.04.10, 17:49

Re: Индексация каталога товаров в ElasticSearch и фасетный поиск.

Сообщение chesar »

ElisDN писал(а): 2017.08.03, 13:20 Не дичь. Так и оставьте. Просто в маппинге обозначте типом 'nested'.
Вернулся сейчас к ES и застрял на агрегациях.
Создал индекс

Код: Выделить всё

 "mappings": {
         "catalog": {
            "properties": {
               "articul": {
                  "type": "text"
               },
               "id": {
                  "type": "integer"
               },
               "name": {
                  "type": "text"
               },
               "price": {
                  "type": "integer"
               }
               "parameters": {
                  "type": "nested"                 
               }
             
            }
         }
Проиндексировал документы

Код: Выделить всё

[
  {
    "id": 1103,
    "articul": "в1103",
    "price": 6270,
    "name": "Виски Macallan \"Fine Oak\" 12 Years Old, with box, 0.7 л",
    "parameters": [
      {"id": "Вкус", "value": ["специи/пряности", "дуб", "сухофрукты", "сбалансированный", "тонкий"]},
      {"id": "Сайт производителя", "value": "http://www.themacallan.com/"},   
      {"id": "Выдержка", "value": "12 лет"},     
      {"id": "Выдержка в бочках", "value": ["европейский дуб", "американский дуб", "из-под бурбона"]},
      {"id": "Упаковка", "value": "В упаковке"}
    ]
  },
  {
    "id": 1104,
    "articul": "в1104",
    "price": 6270,
    "name": "Виски Macallan 12 Years Old, gift box, 0.7 л",
    "parameters": [
      {"id": "Вкус", "value":  ["дым/копченый","специи/пряности","ириска","сухофрукты","херес","мягкий","долгий/продолжительный"]},
      {"id": "Сайт производителя", "value":  "http://www.themacallan.com/"},
      {"id": "Выдержка", "value":  "12 лет"},   
      {"id": "Выдержка в бочках", "value":  "из-под хереса"},
      {"id": "Упаковка", "value":  "В упаковке"},
      {"id": "Бренд", "value":  "Macallan (Макаллан)"}

    ]
  },
  {
    "id": 1105,
    "articul": "в1105",
    "price": 3242,
    "name": "Виски Jack Daniels, 0.7 л",
    "parameters": [
      {"id": "Вкус", "value": ["ваниль", "дым/копченый", "карамель", "древесный"]},  
      {"id": "Сайт производителя", "value": "http://www.jackdaniels.com/"},
      {"id": "Выдержка ", "value": ["белый американский дуб"]},
      {"id": "Упаковка", "value": ["Без упаковки"]},
      {"id": "Бренд", "value": "Jack Daniel's (Джек Дэниэлс)"}
    ]
  }
]
И не могу понять, как построить aggregations чтобы es посчитал мне возможные фильтры
Вкус:
- Дым/копченый (2)
- Специи/пряности (2)
- Дуб (1)
- Ваниль (1)
....
Выдержка в бочках:
- европейский дуб (1)
- американский дуб (1)
- из-под бурбона (1)
- из-под хереса (1)

Не покажите пример запроса не из документации?
Ответить