# Dec 8th, 2020 \[RU\] Rank features для поиска в e-commerce

**URL:** <https://discuss.elastic.co/t/dec-8th-2020-ru-rank-features-e-commerce/256527>\
**Category:** Advent Calendar\
**Created:** [December 8, 2020, 8:00am UTC](https://discuss.elastic.co/t/dec-8th-2020-ru-rank-features-e-commerce/256527 "2020-12-08T08:00:01Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![mayya](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mayya/32/83147_2.png) [@mayya](https://discuss.elastic.co/u/mayya)\
**Post date:** [December 8, 2020, 8:00am UTC](https://discuss.elastic.co/t/dec-8th-2020-ru-rank-features-e-commerce/256527/1 "2020-12-08T08:00:01Z")

</div>

[English version](https://discuss.elastic.co/t/dec-8th-2020-en-rank-features-for-e-commerce-search/256525)

Современный поиск для электронной коммерции должен быть быстрым, релевантным и иметь возможность продвижения определенных результатов. Это статья расскажет как типы полей elasticsearch `rank_feature` и `rank_features` могут помочь в этой цели на примере электронного магазина обуви.

# Проблема № 1: улучшение релевантности

**Проблема № 1:** Нам нужно найти хороший способ ранжирования результатов поиска удовлетворяющих пользовательскому запросу. Сейчас очень распространено применять различные метрики популярности для ранжирования результатов поиска. Эти метрики популярности определяют релевантность документа вне зависимости от пользовательского запроса (алгоритм PageRank Google – известный пример такой метрики). Для нашего магазина обуви такими метриками популярности для определенного товара могут служить количество раз этот товар был просмотрен, куплен нашими пользователями или рейтинг товара по оценкам пользователей.

**Решение** : Один из способов решения данной проблемы – это моделирование метрик популярности обуви с помощью полей `rank_feature`. Для каждой отдельной метрики мы создадим отдельное поле: "views\_count" (количество просмотров), "ordered\_count" (количество заказов) и "rating" (рейтинг обуви):

```auto
PUT shoes
{
  "mappings": {
    "properties": {
      "product_name" : {
       "type" : "text"
      },
      "views_count" : {
        "type" : "rank_feature"
      },
      "ordered_count" : {
        "type" : "rank_feature"
      },
      "rating" : {
        "type" : "rank_feature"
      }
    }
  }
}

```

Проиндексируем примерные документы:

```auto
POST shoes/_bulk
{ "index" : { "_id" : "1"} }
{"product_name" : "Nike Air Zoom Structure", "views_count" : 900, "ordered_count": 14, "rating" : 4.9 }
{ "index" : { "_id" : "2"} }
{"product_name" : "Nike Air Max", "views_count" : 1780, "ordered_count": 17, "rating" : 4.7} 
{ "index" : { "_id" : "3"} }
{"product_name" : "Adidas ULTRABOOST 20", "views_count" : 2560, "ordered_count": 23, "rating" : 4.9}

```

И теперь мы готовы улучшить релевантность текстовых запросов с помощью метрик популярности путем совмещения `match` запроса со специальным `rank_feature` запросом. Например, нижеследующий запрос сперва находит и ранжируют все товары соответствующие пользовательскому запросу, а потом к каждому из этих товаров добавляет дополнительные очки, подсчитанные на основе популярности этого товара. Таким образом, чем более популярен товар с точки зрения количества просмотров, заказов и рейтинга, тем больше увеличится его релевантность и он продвинется выше в списке результатов поиска. Нижеследующий запрос можно настраивать путем использования индивидуальных параметров boost для каждого `rank_feature` запроса в зависимости от того насколько важен каждый из этих метрик популярности.

```auto
GET shoes/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "product_name": <user_query>
          }
        }
      ],
      "should": [
       {
         "rank_feature" : {
           "field" : "views_count"
         }
       },
       {
         "rank_feature" : {
           "field" : "ordered_count"
         }
       },
       {
         "rank_feature" : {
           "field" : "rating"
         }
       } 
      ]
    }
  }
}

```

# Проблема № 2: контроль результатов поиска

**Проблема № 2:** Нам нужно продвигать определенные товары в ответ на определенные запросы пользователя. Такие результаты называются платными или рекламными.

**Решение:** Один из способов решения этой проблемы – это `rank_features` тип поля в elasticsearch. Для каждого товара мы определяем набор категорий которые характеризуют этот товар. Для каждой из категорий товара мы назначаем числовое значение, указывающее насколько мы хотим поднять уровень этого товара когда пользователь ищет по этой категории. Категории могут быть очень разными и разреженными, то есть может быть очень много категорий и каждая категория может применяться только к небольшому количеству товаров. В elasticsearch мы создаем поле "categories" типа `rank_features`:

```auto
PUT shoes
{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text"
      },
      "categories": {
        "type": "rank_features"
      }
    }
  }
}

```

Нижеследующий запрос на индексацию ставит целью продвинуть обувь "Nike" в категории "sneakers" путем назначению более высоких значений для обуви Nike и более низких значений для другой обуви в категории "categories.sneakers".

```auto
POST shoes/_bulk
{ "index" : { "_id" : "1"} }
{"product_name" : "Nike Air Zoom Structure", "categories" : {"sneakers" : 10, "running" : 10, "athleisure" : 2} }
{ "index" : { "_id" : "2"} }
{"product_name" : "Nike Air Max", "categories" : {"sneakers" : 10, "athleisure" : 10} } 
{ "index" : { "_id" : "3"} }
{"product_name" : "Adidas ULTRABOOST 20", "categories" : {"sneakers" : 8, "running" : 10, "athleisure" : 3} }

```

Таким образом, если мы зададим `rank_feature` запрос с "categories.sneakers", обувь "Nike" будет выведена в самом начале списка результатов поиска:

```auto
GET shoes/_search
{
  "query": {
    "rank_feature" : {
      "field": "categories.sneakers"
    }
  }
}

```

Для категории "athleisure", мы увидим совсем другое ранжирование обуви, основанное на числовых значениях назначенных обуви для этой категории.

```auto
GET shoes/_search
{
  "query": {
    "rank_feature" : {
      "field": "categories.athleisure"
    }
  }
}

```

# Технические подробности

Elasticsearch сохраняет значения полей rank\_feature(s) как частоты терминов (term frequency), и rank\_features соответствующие одному и тому же полю будут сохранены в одном поле документа. Например, если поле "categories" имело следующую схему:

```auto
"categories" : {
    "type" : "rank_features"
}

```

Этот запрос на индексацию:

```auto
{ "index" : { "_id" : "1"} }
{"product_name" : "Nike Air Zoom Structure", "categories" : {"sneakers" : 10, "running" : 10, "athleisure" : 2} }

```

создаст документ с полем "categories" у которого будут 3 термина:

1. "sneakers" с частотой термина в 10
2. "running" с частотой термина в 10
3. "athleisure" с частотой термина в 2

Elasticsearch храня все rank features в одном поле, позволяет нам создать их большее количество и избежать бесконтрольного роста схемы (mapping explosion), который бы произошел если бы мы отвели отдельное поле для каждой отдельной категории.

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

# Заключение

Это статья рассказала как поля `rank_feature` и `rank_features` могут быть полезными для настройки релевантности на примере электронного коммерческого магазина. В заключение, мы хотели отметить что настройки релевантности и ранжирования результатов поиска – это сложная и развивающаяся тема. Целью этой статьи не является предписания метода ранжирования, а скорее демонстрация примера как elasticsearch rank\_feature(s) могут помочь в ранжировании результатов.

# Ссылки

- Rank feature(s) документация и блог: [rank\_feature field](https://www.elastic.co/guide/en/elasticsearch/reference/current/rank-feature.html), [rank\_features field](https://www.elastic.co/guide/en/elasticsearch/reference/current/rank-features.html), [rank\_feature query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-rank-feature-query.html), [блог по rank features](https://www.elastic.co/blog/easier-relevance-tuning-elasticsearch-7-0).

- [Flattened field](https://www.elastic.co/guide/en/elasticsearch/reference/current/flattened.html), еще один способ избежать бесконрольного роста схемы.

- [Dense vector](https://www.elastic.co/guide/en/elasticsearch/reference/current/dense-vector.html), еще один тип полей полезный для ранжирования; [блог по dense vectors](https://www.elastic.co/blog/text-similarity-search-with-vectors-in-elasticsearch)

- [Distance Feature query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-distance-feature-query.html), еще один запрос полезный для ранжирования; [блог по distance\_feature query](https://www.elastic.co/blog/distance-feature-query-time-and-geo-in-elasticsearch-result-ranking)

- [Pinned query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html), еще один тип полей полезный для ранжирования

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [January 5, 2021, 8:00am UTC](https://discuss.elastic.co/t/dec-8th-2020-ru-rank-features-e-commerce/256527/2 "2021-01-05T08:00:17Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
