Правильная сортировка для точных совпадений и «начиная с» (префикс) в Elasticsearch - PullRequest
0 голосов
/ 05 февраля 2019

Мне нужно улучшить список результатов поиска с Elasticsearch.

Допустим, у нас есть 3 документа с одним полем и содержимым, подобным этому:

  • "apple"
  • "зеленое яблоко"
  • "яблоня"

Если я ищу "яблоко", может случиться так, что я получу результат, отсортированный так:

  • "зеленое яблоко"
  • "яблоня"
  • "яблоко"

Но я хочу, чтобы точное совпадение имело наивысшийсчет, здесь это документ с «яблоком».

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

Поэтому я хочу, чтобы это было так:

  • "яблоко"
  • "яблоня"
  • "зеленое яблоко"

Iпопытался достичь этого с помощью rescore:

curl -X GET "http://localhost:9200/my_index_name/_search?size=10&pretty" -H 'Content-Type: application/json' -d'
{
   "query": {
      "query_string": {
          "query": "apple"
      }
   },
   "rescore": {
      "window_size": 500,
      "query": {
         "score_mode": "multiply",
         "rescore_query": {
            "bool": {
               "should": [
                  {
                     "match": {
                        "my_field1": {
                           "query": "apple",
                           "boost": 4
                        }
                     }
                  },
                  {
                     "match": {
                        "my_field1": {
                           "query": "apple*",
                           "boost": 2
                        }
                     }
                  }
               ]
            }
         },
         "query_weight": 0.7,
         "rescore_query_weight": 1.2
      }
   }
}'

Но на самом деле это не работает, потому что Elasticsearch, кажется, разделяет все слова пробелами.Например, поиск «apple *» также доставит «зеленое яблоко».Кажется, именно поэтому у меня не работает rescore.

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

Я также поиграл с "match_phrase" в "rescore_query" вместо "bool", но без успеха.

У меня также естьпробовал только с одним совпадением:

curl -X GET "http://localhost:9200/my_index_name/_search?size=10&pretty" -H 'Content-Type: application/json' -d'
{
   "query": {
      "query_string": {
          "query": "apple"
      }
   },
   "rescore": {
      "window_size": 500,
      "query": {
         "score_mode": "multiply",
         "rescore_query": {
            "bool": {
               "should": [
                  {
                     "match": {
                        "my_field1": {
                           "query": "apple*",
                           "boost": 2
                        }
                     }
                  }
               ]
            }
         },
         "query_weight": 0.7,
         "rescore_query_weight": 1.2
      }
   }
}'

И, похоже, работает, но я все еще не уверен.Будет ли это правильным способом?

РЕДАКТИРОВАТЬ1: С другими запросами одно совпадение rescore не работает правильно.

1 Ответ

0 голосов
/ 05 февраля 2019

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

Давайте сначала создадим отображение, как показано ниже:

PUT test
{
  "mappings": {
    "_doc": {
      "properties": {
        "my_field1": {
          "type": "text",
          "analyzer": "whitespace",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

У меня есть поле create my_field1 с анализатором whitespace, чтобы убедиться, что токены созданы с помощьюпробел как единственный разделитель.Во-вторых, я создал подполе с именем keyword типа keyword.keyword будет содержать не проанализированное значение входной строки, и мы будем использовать его для точного соответствия.

Позволяет добавить несколько документов в индекс:

PUT test/_doc/1
{
  "my_field1": "apple"
}

PUT test/_doc/2
{
  "my_field1": "apple tree"
}

PUT test/_doc/3
{
  "my_field1": "green apple"
}

Если использовать нижезапрос для поиска термина apple порядок документов будет 2,1,3.

POST test/_doc/_search
{
  "explain": true,
  "query": {
    "query_string": {
      "query": "apple",
      "fields": [
        "my_field1"
      ]
    }
  }
}

"explain": true в приведенном выше запросе дают шаги вычисления оценки в выходных данных.Прочитав это, вы поймете, как оценивается документ.

Все, что нам нужно сделать, это повысить счет для точного соответствия.Мы проведем точное совпадение с полем my_field1.keyword.У вас может возникнуть вопрос, почему бы не my_field1.Причина этого заключается в том, что анализируется my_field1, когда для входных строк 3 документов генерируются токены, у всех будет токен (термин) apple (вместе с другими терминами, если они есть, например, tree для документа 2и green для документа 3) хранится в этом поле.Когда мы выполняем точное совпадение в этом поле для термина apple, все документы будут совпадать и оказывать одинаковое влияние на оценку для каждого документа и, следовательно, не будет изменений в оценке.Поскольку только один документ имеет точное значение apple против my_field1.keyword, этот документ (doc 1) будет соответствовать точному запросу, и мы увеличим его.Таким образом, запрос будет:

{
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "query": "apple",
            "fields": [
              "my_field1"
            ]
          }
        },
        {
          "query_string": {
            "query": "\"apple\"",
            "fields": [
              "my_field1.keyword^2"
            ]
          }
        }
      ]
    }
  }
}

Выходные данные для запроса выше:

{
  "took": 9,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 1.7260925,
    "hits": [
      {
        "_index": "test3",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.7260925,
        "_source": {
          "my_field1": "apple"
        }
      },
      {
        "_index": "test3",
        "_type": "_doc",
        "_id": "2",
        "_score": 0.6931472,
        "_source": {
          "my_field1": "apple tree"
        }
      },
      {
        "_index": "test3",
        "_type": "_doc",
        "_id": "3",
        "_score": 0.2876821,
        "_source": {
          "my_field1": "green apple"
        }
      }
    ]
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...