Elasticsearch в Python.Как получить целое число из поиска - PullRequest
0 голосов
/ 05 апреля 2019

Я использую эластичный поиск в большой индексированной базе данных.Один из запросов требует найти целочисленное значение и строку, такую ​​как:

s = Search(using=es, index="index1").extra(size=500) \
                        .query("match_phrase", name={"query": "john".casefold()})\
                        .query("match", age="46")

. Будет выполнен поиск записи данных, которая содержит «John white» и «46».Однако, если возраст указан неверно, я хотел бы получить запись, содержащую «Джон Уайт» и возраст, ближайший к «46» (при условии, что у меня есть эти записи, в противном случае он ничего не вернет).

Приведенный выше запрос, однако, возвращает только записи возраста ИМЕННО "46".

Подобный вопрос уже существует на SO: как найти ближайшее / ближайшее число с помощью Query DSL вasticsearch

Но я не уверен, как включить JSON в мой запрос, поскольку я использую определенные модули Python.

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

1 Ответ

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

Я бы порекомендовал использовать сортировку на основе сценариев для достижения этой цели, как описано здесь: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html#_script_based_sorting

Работая в предположении, что вы сопоставляете только имя, - если вы хотите точно соответствовать имени, Я бы порекомендовал использовать совпадение на основе фильтра.В индексе я использовал трех разных «пользователей», определенных следующим образом:

POST index1/_doc
{
  "name": "John White",
  "age": 46
}

POST index1/_doc
{
  "name": "John White",
  "age": 40
}

POST index1/_doc
{
  "name": "John Black",
  "age": 47
}

Мне проще написать что-то более сложное, например, с помощью инструментов разработчика Kibana для тестирования, а затем преобразовать его вPython Elasticsearch DSL-совместимый формат - поэтому в Kibana я в конечном итоге придумал следующее:

GET index1/_search
{
  "query": {
    "match_phrase": {
      "name": {
        "query": "john"
      }
    }
  },
  "sort": {
    "_script": {
      "type": "number",
      "script": {
        "lang": "painless",
        "source": "Math.abs(doc['age'].value - params.target_age)",
        "params": {
          "target_age": 46
        }
      },
      "order": "asc"
    }
  }
}

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

После тестирования и проверки преобразование в Python Elasticsearch DSL довольно просто - вы можете использовать функцию 'Auto Indent', чтобы уменьшить сложность sort и поместите его прямо в существующий оператор.

s = Search(using=es, index="index1").extra(size=500) \
    .query("match_phrase", name={"query": "john".casefold()}) \
    .sort({"_script":{"type":"number","script":{"lang":"painless","source": \
    "Math.abs(doc['age'].value - params.target_age)", \
    "params":{"target_age":46}},"order":"asc"}})

Выполнение этого возвращает ожидаемый ответ:

<Response: [<Hit(index1/_doc/VR3e7WkBsHIsqLp6vfx_): {'name': 'John White', 'age': 46}>, <Hit(index1/_doc/Vx3f7WkBsHIsqLp6DPxM): {'name': 'John Black', 'age': 47}>, <Hit(index1/_doc/Vh3e7WkBsHIsqLp6yfxd): {'name': 'John White', 'age': 40}>]>

Однако, как вы указали, вы хотите ближайший значение, я бы рекомендовал изменить параметр размера на 1.

...