ElasticSearch начинается с запроса на функцию автозаполнения

Я хочу создать функцию автозаполнения с помощью ElasticSearch и C#. Но я не получаю желаемого результата. Для демонстрационных целей это то, что я сделал.

1) Создан индекс под названием «имена»:

PUT names?pretty

2) Добавлено 20 записей с помощью команды POST:

POST names/_doc/1
{
  "name" : "John Smith"
}

3) Список имен:

[ "John Smith", "John Smitha", "John Smithb", "John Smithc", "John Smithd", "John Smithe", "John Smithf",
  "John Smithg", "John Smithh", "John Smithi", "Smith John", "Smitha John", "Smithb John", "Smithc John",
  "Smithd John", "Smithe John", "Smithf John", "Smithg John", "Smithh John", "Smithi John",]

4) Когда я запускаю префиксный запрос:

GET names/_search
{
  "query": {
    "prefix": {
      "name": {
        "value": "Smith"
      }
    }
  }
}

Я ожидаю вернуться "Smith John", "Smitha John"... Но я вернусь "John Smith", "John Smitha"...

Что я делаю не так? Что мне нужно изменить и где?


person Nishith Shah    schedule 30.01.2020    source источник
comment
Пожалуйста, проверьте мой ответ, и было бы лучше предоставить mapping индекса для устранения этих проблем.   -  person user156327    schedule 30.01.2020
comment
Можете ли вы попробовать запустить свой запрос на name.keyword вместо name. Поскольку вы не определили конкретное определение, это может помочь. Если вы хотите пойти дальше с автозаполнением, использование запроса prefix — это только начало, вы можете сделать гораздо больше.   -  person Val    schedule 30.01.2020
comment
@Val Изменение на name.keyword помогло. Можете ли вы объяснить, почему или дать ссылку, чтобы узнать больше об этом? Спасибо!   -  person Nishith Shah    schedule 30.01.2020
comment
Я предоставил больше информации в своем ответе   -  person Val    schedule 18.02.2020


Ответы (2)


Вы определяете поле name как поле text, которое по умолчанию использует standard анализатор и преобразует токены в нижний регистр. Вы можете проверить это с помощью analyze API ЕС.

Пример токенов для анализатора ключевых слов

URL: - http://{{hostname}}:{{port}}/{{index}}/_analyze

{
  "text": "John Smith",
  "analyzer" : "keyword"
}

Вывод вышеуказанного API

{
    "tokens": [
        {
            "token": "John Smith",
            "start_offset": 0,
            "end_offset": 10,
            "type": "word",
            "position": 0
        }
    ]
}

Обратите внимание, что он не нарушает text и не сохраняет его, как описано в официальный документ ES.

Токены со стандартным анализатором

{
  "text": "Smith John",
  "analyzer" : "standard"
}

Вывод вышеуказанного API:

{
    "tokens": [
        {
            "token": "john",
            "start_offset": 0,
            "end_offset": 4,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "smith",
            "start_offset": 5,
            "end_offset": 10,
            "type": "<ALPHANUM>",
            "position": 1
        }
    ]
}

Теперь, когда запрос префикса не анализируется и не отправляется в ES как есть, следовательно, уведомление Smith с заглавной S будет отправлено в ES для сопоставления токенов, теперь с обновленным сопоставлением только документы, начинающиеся с Smith, будут иметь этот префикс, и только они будут прийти в результатах поиска.

Отображение

{
    "mappings": {
        "properties": {
            "name": {
                "type": "text",
                "analyzer": "keyword"
            }
        }
    }
}

Поисковый запрос

{
    "query": {
        "prefix": {
            "name": {
                "value": "Smith"
            }
        }
    }
}

EDIT: :- ** Обновлен параметр на основе комментариев OP и на основе вышеуказанного параметра и поискового запроса, он получает только результаты, начинающиеся с Smith, как показано в приведенном ниже выводе.

{
  "took": 811,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 5,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "59977669",
        "_type": "_doc",
        "_id": "6",
        "_score": 1.0,
        "_source": {
          "name": "Smith John"
        }
      },
      {
        "_index": "59977669",
        "_type": "_doc",
        "_id": "7",
        "_score": 1.0,
        "_source": {
          "name": "Smithb John"
        }
      },
      {
        "_index": "59977669",
        "_type": "_doc",
        "_id": "8",
        "_score": 1.0,
        "_source": {
          "name": "Smithc John"
        }
      },
      {
        "_index": "59977669",
        "_type": "_doc",
        "_id": "9",
        "_score": 1.0,
        "_source": {
          "name": "Smithd John"
        }
      },
      {
        "_index": "59977669",
        "_type": "_doc",
        "_id": "10",
        "_score": 1.0,
        "_source": {
          "name": "Smithe John"
        }
      }
    ]
  }
}
person user156327    schedule 30.01.2020
comment
Я удалил старый индекс, создал новый индекс с предоставленными вами настройками и сопоставлениями, вставил данные и выполнил запрос. Я все еще получаю Джона Смита в качестве первого результата, а не Смита Джона. Старые сопоставления: { "names" : { "mappings" : { "properties" : { "name" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } } - person Nishith Shah; 31.01.2020
comment
@NishithShah, я обновил свой ответ на основе ваших комментариев, а также добавил более подробное объяснение, пожалуйста, просмотрите его и дайте мне знать, если у вас есть какие-либо вопросы. - person user156327; 18.02.2020

Вам нужно запустить префиксный запрос в поле name.keyword, а не в поле name.

GET names/_search
{
  "query": {
    "prefix": {
      "name.keyword": {
        "value": "Smith"
      }
    }
  }
}

Причина в том, что поле name.keyword имеет тип keyword и не анализируется (т. е. индексируется один токен John Smith), и, следовательно, вы можете выполнить запрос на точное совпадение с ним. Поле name имеет тип text и анализируется (т. е. два токена john и smith индексируются), и, следовательно, ваш запрос на точное совпадение (или совпадение префикса) не работает.

Вы можете прочитать больше об этом здесь

person Val    schedule 30.01.2020
comment
да, это сработало, но в итоге я использовал Completion Suggester. Спасибо за вашу помощь. - person Nishith Shah; 20.02.2020