Elasticsearch: моделирование цены продукта и проблема запроса - PullRequest
0 голосов
/ 02 июня 2019

Я хочу использовать Elasticsearch для повышения производительности при поиске товаров (duh) в решении для электронной коммерции.У нас есть модель данных, в которой продукт может иметь несколько вариантов, и у каждого варианта может быть одна или несколько цен (иногда довольно значительное количество цен).

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

Мой первый подход состоял в денормализации продукта/ варианты и имеют цены как вложенные поля, но это было довольно медленно, и у меня было несколько проблем с сортировкой (я думаю о цене, но точные детали ускользают от меня прямо сейчас).

Второй подход заключался в полной денормализации, поэтому вся комбинация продукт / вариант / цена представляется в виде документа.Этот подход намного быстрее (очевидно), я могу агрегировать по productId или variantId и получать самую низкую цену, но проблема в том, что я не могу отсортировать агрегаты по нечисловым или неагрегированным полям.

Денормализованные документы (productId, variantId - поля ключевых слов, price - числовые, validFrom / - To - даты, а остальные текстовые):

[
  {
    "productId": "111-222-333",
    "variantId": "aaa-bbb-ccc",
    "product_title": "Mega-product",
    "product_description": "This awesome piece of magic will change your life",
    "variant_title": "Green mega-product",
    "variant_description": "Behold the awesomeness of the green magic mega-product",
    "color": [
      "blue",
      "green"
    ],
    "brand": "DaBrand",
    "validFrom": "2019-06-01T00:00:00Z",
    "validTo": null,
    "price": 399
  },
  {
    "productId": "111-222-333",
    "variantId": "aaa-bbb-ddd",
    "product_title": "Mega-product",
    "product_description": "This awesome piece of magic will change your life",
    "variant_title": "Blue mega-product",
    "variant_description": "Behold the awesomeness of the blue magic mega-product",
    "color": [
      "blue",
      "green"
    ],
    "brand": "DaBrand",
    "validFrom": "2019-06-01T00:00:00Z",
    "validTo": null,
    "price": 499
  },
  {
    "productId": "111-222-333",
    "variantId": "aaa-bbb-ddd",
    "product_title": "Mega-product",
    "product_description": "This awesome piece of magic will change your life",
    "variant_title": "Blue mega-product",
    "variant_description": "Behold the awesomeness of the blue magic mega-product",
    "color": [
      "blue",
      "green"
    ],
    "brand": "DaBrand",
    "validFrom": "2019-06-05T00:00:00Z",
    "validTo": "2019-06-10T00:00:00Z",
    "price": 399
  }
]

Примеррабочий запрос, где я сортирую по агрегированной цене.

{
    "size": 1,
    "sort": {
        "product_name_text_en.keyword": "asc"
    },
    "query": {
        // All the query and filtering
    },
    "aggs": {
        "by_product_id": {
            "terms": {
                "field": "product_id_string",
                "order": {
                    "min_price": "desc"
                }
            },
            "aggs": {
                "min_price": {
                    "min": {
                        "field": "price_decimal"
                    }
                }
            }
        }
    }
}

Однако, используя этот подход, я не могу найти способ сортировки по полям документа.Это возможно (я думаю) для числовых, логических полей и полей даты, используя bucket_sort, но мне нужно иметь возможность сортировать, например, поле бренда или заголовка (которые являются текстовыми).Если бы было возможно order при агрегации top_hits, я был бы дома свободен, но, к сожалению, это невозможно, как я понял из документации (я также попробовал это просто, чтобы убедиться).

Может кто-нибудь направить меня к лучшему решению?Я не возражаю, если мне придется выполнить запрос в два этапа, но для того, чтобы это работало для сортировки, мне, вероятно, нужно иметь несколько разных «типов документов», таких как Product, Variant, ProductPrice и VariantPrice для использования в зависимости от запрошенногоПорядок сортировки.Я далеко не так далеко, так что окончательное ремоделирование находится на столе, я рассмотрел использование полей соединения, но я не уверен, что это будет эффективным.

Так как количество продуктов и вариантов (и цен) может быть значительным - миллион продуктов определенно находится на столе, я думаю, что у меня будут проблемы с получением идентификаторов из запроса (например, фильтрация по бренду и сортировка поtitle), а затем отправьте их в запрос на получение наилучшей цены.

1 Ответ

1 голос
/ 03 июня 2019

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

Индекс имеет ту же модель, что и в моем первоначальном вопросе, но запрос стал намного проще:

{
  "size": 10,
  "query": {
    // filter/match stuff, including filtering valid prices.
  },
  "collapse": {
    "field": "productId",
    "inner_hits": {
      "name": "least_price",
      "collapse": {
        "field": "price"
      },
      "size": 1,
      "sort": [
        {
          "price": "asc"
        }
      ]
    }
  },
  "sort": [
    {
      "brand.keyword": "asc"
    }
  ]
}

И возвращать вариантывместо продуктов я просто сворачиваюсь на variantId

Свертывание основано на productId или variantId, а least_price для inner_hits возвращает документ с наименьшей ценой (asc отсортированопо цене и выбору первого) документа, соответствующего моим критериям.Работает как шарм.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...