Заполнение и сортировка ElasticSearch Boost по дате

Я пытаюсь увеличить запрос по полям, а затем отсортировать их по дате:

        multiMatchQuery.fields(columnSortOrder());
        searchSourceBuilder.trackScores(true);
        searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
        searchSourceBuilder.sort("updated_time",SortOrder.DESC);

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

Заказ на ускорение

Field_A^3
Field_B^2
Field_C^1

образец данных:

{
  "_source": {
    "updated_time": "2020-01-04T01:00:06.870000Z",
    "field_A": "Slovakia beyond",
    "filed_B": "The properties in Slovakia are beyound...",
    "Field_C": "Once you fix the relevance then sorting should work correctly."
  }

  {
  "_source": {
    "updated_time": "2020-02-04T01:00:06.870000Z",
    "field_A": "**beyond** filed_A",
    "filed_B": "The properties in Japan is high",
    "Field_C": "Test description for filed_A"
  }

    {
  "_score": 2.56865,
  "_source": {
    "updated_time": "2020-01-04T01:00:06.870000Z",
    "field_A": "Test filed_B",
    "filed_B": "**beyond** is search  term in filed_B",
    "Field_C": "Test description for filed_B"
  }

      {
  "_source": {
    "updated_time": "2020-02-04T01:00:06.870000Z",
    "field_A": "Test filed_B",
    "filed_B": "**beyond** is search  term in filed_B Test for Feb",
    "Field_C": "Test description for filed_B test for Feb"
  }

     {
    "_source": {
    "updated_time": "2020-02-04T01:00:06.870000Z",
    "field_A": "Search Term filed_C",
    "filed_B": " is the search term for lowest column",
    "Field_C": "**beyond** Test description for filed_C "
  }

предположим, что поисковый запрос выходит за рамки. Если поисковый запрос найден в [field_A, field_B, filed_C] Ожидаемый результат:

[первоочередная сортировка Field_A по дате]

  1. Словакия после января 2020 года
  2. Beyond filed_A Февраль 2020 г.

[второй приоритет Field_B, сортировка по дате]

  1. за пределами поискового запроса в filed_B Январь 2020
  2. за пределами поискового запроса в filed_B Test за февраль 2020 г.

[Поле третьего приоритета, сортировка по дате]

  1. Beyond Test описание для filed_C Февраль 2020

person Talha Bin Shakir    schedule 16.05.2020    source источник
comment
Вы пробовали это?   -  person Gibbs    schedule 16.05.2020
comment
Не могли бы вы дополнить ответ примером запросов для Field_A, Field_B и т. Д.? Это полное или точное совпадение? Подскажите, пожалуйста, если есть совпадение в Field_A, но его последний document_date - 2018 год, должно ли оно быть в результирующем наборе выше, чем Field_B, 2020?   -  person Nikolay Vasiliev    schedule 17.05.2020
comment
@NikolayVasiliev, это не точное совпадение, и да, вы правы, если совпадение найдено в Field_A, оно должно быть выше независимо от дат, но если в Field_A найдено более одного совпадения, с датами ex (2018,2020,2019), тогда Field_A следует соответственно отсортировать по дате. Я добавил примерную дату, о которой идет речь, и с ожидаемым результатом Спасибо   -  person Talha Bin Shakir    schedule 18.05.2020


Ответы (2)


Это могло быть из-за этого

При сортировке по полю оценки не вычисляются. Если для параметра track_scores установлено значение true, оценки по-прежнему будут вычисляться и отслеживаться.

Так что включите track_scores для вашего запроса.

Java API

Используйте trackScores с параметризованной вариацией.

А также

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

   {
     "_score": {
        "order": "desc"
     }
    }

Добавьте это как первую сортировку, а затем отсортируйте по дате DESC. Это работает, как показано ниже.

Если поисковый запрос является частью более чем одного поля [field1, field2, field3], тогда будет рассчитана общая оценка.

person Gibbs    schedule 16.05.2020
comment
@Val Не могли бы вы проверить это? - person Gibbs; 16.05.2020
comment
Да, я пробовал, но приоритеты делались по очкам, но не по дате. На самом деле я хочу, чтобы поисковый запрос был найден в [field1, field2, field3], результат должен быть установлен наверху [field1] и отсортирован по дате после сортировки [filed2] по дате и сортировки [field3] по дате, как я определил усиление поля [Поле_A ^ 3 Поле_B ^ 2 Поле_C ^ 1]. Я не хочу сортировать результат с подсчетом очков. - person Talha Bin Shakir; 17.05.2020
comment
Не могли бы вы привести несколько примеров данных, в которых вы столкнулись с проблемой. - person Gibbs; 17.05.2020
comment
Я добавил несколько образцов данных с ожидаемым результатом, на самом деле критерием является увеличение столбца, а затем их сортировка по дате. Все совпадения, найденные в поле A, должны быть первыми, но среди друг друга они также должны быть отсортированы по дате. - person Talha Bin Shakir; 18.05.2020
comment
Не могли бы вы также добавить сопоставление для полей? - person Gibbs; 19.05.2020

Есть несколько способов сделать это. Есть более чистый подход с несколькими запросами (с использованием Multi API поиска) и более сложный подход с одним запросом (с использованием _ 1_ query). Позвольте мне объяснить вам, как это сделать.

Более чистый подход с использованием _msearch

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

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

Почему не сработали другие подходы?

Вы уже знаете о простой настройке оценки за счет усиления одних полей над другими, как в этом примере _ 5_ запрос:

POST /myscores/_search
{
    "query": {
        "multi_match": {
            "query": "beyond",
            "fields": ["field_A^3", "filed_B^2", "Field_C^1"]
        }
    }
}

Это просто возьмет результат совпадения, умноженный на 3, если он совпадает с field_A, умноженный на 2, если filed_B, и т. Д.

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

Как вы уже пробовали, если вы попросите Elasticsearch использовать updated_time в качестве меры сортировки, он проигнорирует результат сопоставления, что нежелательно.

Предложение товарища Гиббса также, похоже, не сработало, потому что использование сортировки по _score, а затем по updated_time (или наоборот ) игнорировал тот или иной вариант.

Есть ли способ объединить _score и updated_time?

Есть, попробуем использовать function_score:

POST /myscores/_search
{
    "query": {
        "function_score": {
            "query": {
                "multi_match": {
                    "query": "beyond",
                    "fields": [
                        "field_A^3",
                        "filed_B^2",
                        "Field_C"
                    ]
                }
            },
            "score_mode": "max",     
            "boost_mode": "multiply", <=== 2
            "field_value_factor": {   <=== 1
                "field": "updated_time",   
                "factor": 0.00000000001,
                "missing": 1
            }
        }
    }
}

function_score позволяет вы можете точно настроить оценку запроса.

Мы берем multi_match запрос, с которым мы уже знакомы из раздела выше, и пытаемся изменить его.

Во-первых, мы знаем, что хотим принять во внимание updated_time. Мы используем _ 19_ как функция для изменения оценки (точка 1 в запросе выше).

Теперь мы говорим ему умножить значение updated_time на оценку запроса - установив boost_mode на multiply (пункт 2).

Выполнение этого запроса даст примерно следующее:

"hits": [
  {
    ...
    "_score": 43.121338,
    "_source": {
      "updated_time": "2020-02-04T01:00:06.870000Z",
      "field_A": "**beyond** filed_A",
      "filed_B": "The properties in Japan is high",
      "Field_C": "Test description for filed_A"
    }
  },
  {
    ...
    "_score": 43.048275,
    "_source": {
      "updated_time": "2020-01-04T01:00:06.870000Z",
      "field_A": "Slovakia beyond",
      "filed_B": "The properties in Slovakia are beyound...",
      "Field_C": "Once you fix the relevance then sorting should work correctly."
    }
  },
  {
    ...
    "_score": 29.028637,
    "_source": {
      "updated_time": "2020-01-04T01:00:06.870000Z",
      "field_A": "Test filed_B",
      "filed_B": "**beyond** is search  term in filed_B",
      "Field_C": "Test description for filed_B"
    }
  },
  {
    ...
    "_score": 24.44329,
    "_source": {
      "updated_time": "2020-02-04T01:00:06.870000Z",
      "field_A": "Test filed_B",
      "filed_B": "**beyond** is search  term in filed_B Test for Feb",
      "Field_C": "Test description for filed_B test for Feb"
    }
  },
  {
    ...
    "_score": 23.517717,
    "_source": {
      "updated_time": "2020-02-04T01:00:06.870000Z",
      "field_A": "Search Term filed_C",
      "filed_B": " is the search term for lowest column",
      "Field_C": "**beyond** Test description for filed_C "
    }
  }
] 

Обратите внимание, что оценки field_A совпадений близки друг к другу, но немного отличаются от оценок filed_B.

Также обратите внимание, что заказ updated_time является самым последним первым; Сейчас мы обратимся к обратному порядку.

Как использовать updated_time для сортировки в обратном порядке?

field_value_factor позволяет умножить исходное значение из поля на некоторый коэффициент.

Внутри Elasticsearch хранит даты как временные метки unix. Это целое число из 10 цифр, что буквально на ~ 10 порядков больше, чем оценка ES, которую я получил. Поэтому я решил сделать их сопоставимого порядка:

            "field_value_factor": {
                "field": "updated_time",   
                "factor": 0.00000000001,
                "missing": 1
            }

Теперь это дает нам эквивалент SORT BY updated_time DESC:

Feb 2020
Jan 2020

Но что, если нам нужно, чтобы это было SORT BY updated_time ASC?

Jan 2020
Feb 2020

Мы не можем умножать на отрицательный коэффициент, потому что оценки в Elasticsearch должны быть положительными действительными числами.

Вместо этого мы можем изменить исходное значение с помощью 1/x, как здесь:

        "field_value_factor": {
            "field": "updated_time",
            "factor": 0.00000000001,
            "missing": 1,
            "modifier": "reciprocal"  <=== 1/x
        }

Это, наконец, даст нам порядок, о котором вы просили в вопросе:

"hits": [
  {
    ...
    "_score": 0.17285699,
    "_source": {
      "updated_time": "2020-01-04T01:00:06.870000Z",
      "field_A": "Slovakia beyond",
      "filed_B": "The properties in Slovakia are beyound...",
      "Field_C": "Once you fix the relevance then sorting should work correctly."
    }
  },
  {
    ...
    "_score": 0.1725641,
    "_source": {
      "updated_time": "2020-02-04T01:00:06.870000Z",
      "field_A": "**beyond** filed_A",
      "filed_B": "The properties in Japan is high",
      "Field_C": "Test description for filed_A"
    }
  },
  {
    ...
    "_score": 0.116562225,
    "_source": {
      "updated_time": "2020-01-04T01:00:06.870000Z",
      "field_A": "Test filed_B",
      "filed_B": "**beyond** is search  term in filed_B",
      "Field_C": "Test description for filed_B"
    }
  },
  {
    ...
    "_score": 0.0978178,
    "_source": {
      "updated_time": "2020-02-04T01:00:06.870000Z",
      "field_A": "Test filed_B",
      "filed_B": "**beyond** is search  term in filed_B Test for Feb",
      "Field_C": "Test description for filed_B test for Feb"
    }
  },
  {
    ...
    "_score": 0.09411382,
    "_source": {
      "updated_time": "2020-02-04T01:00:06.870000Z",
      "field_A": "Search Term filed_C",
      "filed_B": " is the search term for lowest column",
      "Field_C": "**beyond** Test description for filed_C "
    }
  }

Как это сделать на Java?

Хотя я не могу предоставить вам готовый код, я считаю, что вы можете начать с FunctionScoreBuilder и попробуйте интегрировать его с существующим кодом.


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

person Nikolay Vasiliev    schedule 19.05.2020