_Score = null при сортировке по другому полю

(Jack Daniels) #1

У меня такая проблема что я не могу сделать релевантную сортировку

у меня есть запрос на продукты :

"query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "apple Iphone XR 128GB",
            "fields": [
              "model.ngram",
              "name.ngram",
              "vendor.ngram",
              "model^3",
              "vendor^2"
            ]
          }
        }
      ],
      "filter": {
        "term": {
          "cur": "russia"
        }
      }
    }
  }

он выдает мне такой результат :

"hits" : {
    "total" : 19271,
    "max_score" : 104.822586,
    "hits" : [
      {
        "_index" : "product",
        "_type" : "default",
        "_id" : "4672676",
        "_score" : 104.822586,
        "_source" : {
          "id" : "4672676",
          "cur" : "russia",
          "price" : 64990.0,
          "model" : null,
          "name" : "Apple iPhone XR 128GB (черный)",
< ... >

Все отлично , теперь я хочу избавиться от мусора и отсортировать полученый результат по полю "name"... тоесть я ограничиваю скор , и перь то что у меня получилось хочу отсортировать по полю name

я добавляю в свой запрос ограничение на скор и сортировку :

"query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "apple Iphone XR 128GB",
            "fields": [
              "model.ngram",
              "name.ngram",
              "vendor.ngram",
              "model^3",
              "vendor^2"
            ]
          }
        }
      ],
      "filter": {
        "term": {
          "cur": "russia"
        }
      }
    },  
  "min_score": 40,
  "sort": [
    {
      "name.keyword": {
        "order": "desc"
      }
    }
  ]
  }

В итоге я получаю вот это во ...

  "hits" : {
    "total" : 431,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "product",
        "_type" : "default",
        "_id" : "ad_2271_89495",
        "_score" : null,
        "_source" : {
          "id" : "ad_2271_89495",
          "cur" : "russia",
          "price" : 1990.0,
          "model" : "Touch Case для Apple iPhone Xs, светло-розовый",
          "name" : "Чехол для смартфона uBear Touch Case для Apple iPhone Xs, светло-розовый",
    < ... >

мало того с что скор null так еще и поиск сломаны

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

properties "name" если нужно

"name": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword",
          "normalizer": "keyword_lowercase"
        },
        "ngram": {
          "type": "text",
          "analyzer": "custom_ngram"
        },
        "ru": {
          "type": "text",
          "analyzer": "russian"
        }
      },
      "analyzer": "standard"
    }

Помогите пожалуйста!

(Igor Motov) #2

Какая версия elasticsearch?

Что получается если заменить sort на

  "sort": [
    {
      "name.keyword": {
        "order": "asc"
      }
    },
    {
      "_score": {
        "order": "desc"
      }
    }
  ]
(Jack Daniels) #3

Версия 6.7.0

 "version" : {
    "number" : "6.7.0",
    "build_flavor" : "oss",
    "build_type" : "docker",
    "build_hash" : "8453f77",
    "build_date" : "2019-03-21T15:32:29.844721Z",
    "build_snapshot" : false,
    "lucene_version" : "7.7.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  }

Да я пробовал такие методы.

При варианте:

  "sort": [{
            "name.keyword": {"order": "asc"}
           },
           {
            "_score": {"order": "desc"}
          }]

Выдает результат абсолютно идентичный:

 "sort": [{
     "_score": {"order": "asc" }
   }]

в ответе поле сортировки которое добовляется в ответ выглядит так

        "sort" : [
         "greenconnect кабель 0.5m apple usb 2.0  am/lightning 8 pin  для iphone 5/6/7/8/x - поддержка всех io",
          40.810375 
        ]

А При таком способе :

"sort": [{
           "_score": { "order": "desc" }
         },
        {
          "name.keyword": {"order": "asc"}
        }]

Выдает результат как если вообще не использовать сортировку ( ну собственно дефолтный вариант с сортировкой по убыванию _score)
в ответе поле сортировки выглядит так

        "sort" : [
          101.63835,
          null
        ]

когда есть скор и релевантный поиск
но никакой сортировке нет
ибо продукты идут след образом

"name" : "Apple iPhone XR 128GB (белый)",
"name" : "Apple iPhone XR 128GB (черный)",
"name" : "Apple iPhone XR 128GB (коралловый)",
"name" : "Apple iPhone 7 128GB (черный)",
"name" : "Смартфон Apple iPhone XR 128GB черный",
"name" : "Смартфон Apple iPhone XR 128GB желтый",
"name" : "Смартфон Apple iPhone XR 128GB коралловый",

Ну и собственно вопорос в том как сделать:

  1. можно ли как-то сделать чтобы сохранялся _score про сортировке по одному полю name и был +- релевантный поиск

  2. можно ли про использование сортировке по _score как то там еще и внутри сортировать ? или чтото близкое к этому

стремлюсь к примерно такому варианту .... (Пример правда с Apple iPhone не очень удачный , но думаю суть понятна )

"name" : "Apple iPhone XR 128GB (белый)",
"name" : "Apple iPhone XR 128GB (коралловый)",
"name" : "Apple iPhone XR 128GB (черный)",
"name" : "Смартфон Apple iPhone XR 128GB желтый",
"name" : "Смартфон Apple iPhone XR 128GB коралловый",
"name" : "Смартфон Apple iPhone XR 128GB черный",
"name" : "Apple iPhone 7 128GB (черный)",

(Igor Motov) #4

Да в том и дело, что все это должно работать без проблем, и когда я пытаюсь воспроизвести проблему - у меня все работает:

DELETE test

PUT test/_doc/1
{
  "text": "foo bar baz"
}

PUT test/_doc/2
{
  "text": "foo foo baz"
}

PUT test/_doc/3
{
  "text": "foo foo foo"
}

POST test/_search
{
  "query": {
    "match": {
      "text": "foo"
    }
  },
  "min_score": 0.3,
  "sort": [
    {
      "text.keyword": {
        "order": "asc"
      }
    },
    {
      "_score": {
        "order": "desc"
      }
    }
  ]
}

выдает:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.39556286,
        "_source" : {
          "text" : "foo foo baz"
        },
        "sort" : [
          "foo foo baz",
          0.39556286
        ]
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.45207188,
        "_source" : {
          "text" : "foo foo foo"
        },
        "sort" : [
          "foo foo foo",
          0.45207188
        ]
      }
    ]
  }
}
(Jack Daniels) #5

Спасибо! Ваш пример меня на толкнул на мысль которая решила мою проблему!
ну отчасти но для меня это достаточно.

Проблема оказывается была в том что в мой базе очень много продуктов
и мой scor начинался от 0.8 до 98

и то что я выставлял min_score: 40 было попросту недостаточно

после вашего ответа , я решил взять 10% от моего score и все в результате получилось

где-то до 30% еще сохраняется +- релевантность поиска и сортировка, если брать больше то все становится печально )