Условная сортировка ElasticSearch по разным полям, если в диапазоне - PullRequest
0 голосов
/ 25 октября 2018

У меня есть продукты, и некоторые из них снижены в цене для определенного диапазона дат.(упрощенный) пример продукции:

{
  "id": 1,
  "price": 2.0,
  "specialPrice": {
    "fromDate": null,
    "tillDate": null,
    "value": 0,
  },
},
{
  "id": 2,
  "price": 4.0,
  "specialPrice": {
    "fromDate": 1540332000,
    "tillDate": 1571781600,
    "value": 2.5,
  },
},
{
  "id": 3,
  "price": 3.0,
  "specialPrice": {
    "fromDate": null,
    "tillDate": null,
    "value": 0,
  },
}

Фильтрация по цене не была проблемой.Это я мог бы сделать с помощью простого запроса bool.

Но я пока не смог найти хороший пример сценариев ElasticSearch, которые могли бы указывать мне правильное направление, даже если он должен быть довольно простым, если вы знаете синтаксис.

Мой псевдокод: price = ('now' between specialPrice.fromDate and specialPrice.tillDate) ? specialPrice.value : price

Есть ли способ перевести это во что-то, что будет работать в сортировке ElasticSearch?

Чтобы уточнить далее: по умолчанию всепродукты уже отсортированы по нескольким условиям.Пользователь также может искать любые термины и фильтровать результаты, а также может выбрать несколько параметров сортировки.Например, элементы могут быть отсортированы по тэгам, а затем по цене, все это очень динамично и впоследствии все же сортирует эти результаты по некоторым другим свойствам (включая _score).Так что просто изменить _score было бы плохо, так как он уже рассчитан на сложную задачу, чтобы показать наилучшие результаты для заданных поисковых терминов.

Вот мой текущий скрипт, который не срабатывает при первом params.currentDate:

"sort": {
"_script": {
  "type": "number",
  "script": {
    "source": "if(doc['specialPrice.tillDate'] > params.currentDate) {params.currentPrice = doc['specialPrice.value']} return params.currentPrice",
    "params": {
      "currentDate": "now",
      "currentPrice": "doc['price']"
    }
  }
}

Как это работает сейчас: Одной из проблем было вложение некоторых свойств.Поэтому одним из моих шагов было дублирование их содержимого в новых полях для продукта (что меня не очень радует, но все равно).Поэтому в своем отображении я создал новые свойства для продуктов (specialFrom, specialTill, specialValue) и передал соответствующие поля в свойствах specialPrice «copy_to» с новыми именами свойств.Эта часть имеет синтаксис массива php, так как я использую ruflin /astica:

            'specialPrice' => [
                'type' => 'nested',
                'properties' => [
                    'fromDate' => [
                        'type' => 'date',
                        'format' => 'epoch_second',
                        'copy_to' => 'specialFrom',
                    ],
                    'tillDate' => [
                        'type' => 'date',
                        'format' => 'epoch_second',
                        'copy_to' => 'specialTill',
                    ],
                    'value' => [
                        'type' => 'float',
                        'copy_to' => 'specialValue',
                    ],
                ],
            ],
            'specialFrom' => [
                'type' => 'date',
                'format' => 'epoch_second',
            ],
            'specialTill' => [
                'type' => 'date',
                'format' => 'epoch_second',
            ],
            'specialValue' => [
                'type' => 'float',
            ],

Теперь мой скрипт сортировки сортировки выглядит следующим образом (в моем тестирующем клиенте все еще работаю над его реализацией вastica):

"sort": {
"_script": {
  "type": "number",
  "script": {
    "lang": "painless",
    "source": "params.param = ((doc['specialTill'].value - new Date().getTime()) > 0 && (new Date().getTime() - doc['specialFrom'].value) > 0) ? doc['specialValue'].value : doc['price'].value; return params.param;",
    "params": {
      "param": 0.0
    }
  }
}

}

Я не на 100% доволен этим, потому что у меня есть избыточные данные и сценарии (дважды вызывая new Date().getTime() в сценарии), но это работает, и этосамое главное на данный момент:)

1 Ответ

0 голосов
/ 25 октября 2018

Я обновил приведенный ниже запрос и оставил ваши пояснения.Дайте мне знать, если это работает!

POST dateindex/_search
{  
   "query":{  
      "match_all":{  // you can ignore this, I used this to test at my end

      }
   },
   "sort":{  
      "_script":{  
         "type":"number",
         "script":{  
            "lang":"painless",
            "inline":" params.param = ((doc['specialPrice.tillDate'].value - new Date().getTime()) > 0) ? doc['specialPrice.value'].value : doc['price'].value; return params.param;",
            "params":{  
               "param":0.0
            }
         },
         "order":"asc"
      }
   }
}

Вы можете попробовать использовать source вместо inline в приведенном выше запросе, так как я тестировал версию ES5.X на моей машине.

Надеюсь, это поможет!

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