Поиск имени в ElasticSearch

У меня есть индекс, созданный в ElasticSearch с именем поля, где я храню полное имя человека: имя и фамилия. Я хочу выполнить полнотекстовый поиск по этому полю, поэтому я проиндексировал его с помощью анализатора.

Теперь моя проблема в том, что если я ищу: «Джон Рэм Рэм»

И в индексе у меня было «Удача Джона Рама Рама», это значение имеет более высокий балл, чем «Джон Рам Рам». Есть ли возможность получить лучший результат в точном поле, чем в поле с большим количеством значений в строке?

Заранее спасибо!


person sayfra85    schedule 12.04.2017    source источник


Ответы (1)


Я разработал небольшой пример (при условии, что вы используете ES 5.x из-за разницы в подсчете очков):

DELETE test
PUT test
{
  "settings": {
    "similarity": {
      "my_bm25": {
        "type": "BM25",
        "b": 0
      }
    }
  },
  "mappings": {
    "test": {
      "properties": {
        "name": {
          "type": "text",
          "similarity": "my_bm25",
          "fields": {
            "length": {
              "type": "token_count",
              "analyzer": "standard"
            }
          }
        }
      }
    }
  }
}

POST test/test/1
{
  "name": "John Rham Rham"
}
POST test/test/2
{
  "name": "John Rham Rham Luck"
}
GET test/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "name": {
            "query": "John Rham Rham",
            "operator": "and"
          }
        }
      },
      "functions": [
        {
          "script_score": {
            "script": "_score / doc['name.length'].getValue()"
          }
        }
      ]
    }
  }
}

Этот код делает следующее:

  • Замените реализацию BM25 по умолчанию на пользовательскую, изменив параметр B (нормализация длины поля). Вы также можете изменить сходство с «классическим», чтобы вернуться к TF/IDF, в котором нет этой нормализации.
  • Создайте внутреннее поле для поля вашего имени, которое подсчитывает количество токенов внутри поля вашего имени.
  • Обновите счет в соответствии с длиной токена

Это приведет к:

"hits": {
    "total": 2,
    "max_score": 0.3596026,
    "hits": [
      {
        "_index": "test",
        "_type": "test",
        "_id": "1",
        "_score": 0.3596026,
        "_source": {
          "name": "John Rham Rham"
        }
      },
      {
        "_index": "test",
        "_type": "test",
        "_id": "2",
        "_score": 0.26970196,
        "_source": {
          "name": "John Rham Rham Luck"
        }
      }
    ]
  }
}

Не уверен, что это лучший способ сделать это, но, возможно, он укажет вам правильное направление :)

person Byron Voorbach    schedule 12.04.2017