Поиск по точному совпадению во всех полях Elasticsearch - PullRequest
1 голос
/ 06 июля 2019

Допустим, у меня есть 3 документа, каждый из которых содержит только одно поле (но давайте представим, что их больше, и нам нужно выполнить поиск по всем полям).

  1. Значение поля "сначала"second "
  2. Значение поля -" второй первый "
  3. Значение поля -" первый второй третий "

Вот скрипт, который можно использовать для создания этих 3документы:

# drop the index completely, use with care!
curl -iX DELETE 'http://localhost:9200/test'

curl -H 'content-type: application/json' -iX PUT 'http://localhost:9200/test/_doc/one' -d '{"name":"first second"}'
curl -H 'content-type: application/json' -iX PUT 'http://localhost:9200/test/_doc/two' -d '{"name":"second first"}'
curl -H 'content-type: application/json' -iX PUT 'http://localhost:9200/test/_doc/three' -d '{"name":"first second third"}'

Мне нужно найти единственный документ (документ 1), который имеет ровно «первый второй» текст в одном из своих полей.

Вот что я пытался.

А.Простой поиск:

curl -H 'Content-Type: application/json' -iX POST 'http://localhost:9200/test/_search' -d '{
  "query": {
    "query_string": {
      "query": "first second"
    }
  }
}'

возвращает все 3 документа

B.Цитирование

curl -H 'Content-Type: application/json' -iX POST 'http://localhost:9200/test/_search' -d '{
  "query": {
    "query_string": {
      "query": "\"first second\""
    }
  }
}'

дает 2 документа: 1 и 3, поскольку оба содержат «первую секунду».

Здесь https://stackoverflow.com/a/28024714/7637120 они предлагают использовать анализатор «ключевых слов» для анализаполя при индексации, но я бы хотел избежать каких-либо настроек сопоставления.

Можно ли их избежать и при этом найти только документ 1?

1 Ответ

1 голос
/ 06 июля 2019

Да, вы можете сделать это, объявив name тип отображения как keyword. Ключ к решению вашей проблемы прост - объявите name mapping type:keyword и начинайте

чтобы продемонстрировать это, я сделал это

1) created mapping with `keyword` for `name` field`
2) indexed the three documents
3) searched with a `match` query

1011 * Отображения *

PUT so_test16
{
  "mappings": {
    "_doc":{
      "properties":{
        "name": {
          "type": "keyword"

        }
      }
    }
  }
}

Индексирование документов

POST /so_test16/_doc
{
    "id": 1,
    "name": "first second"
}
POST /so_test16/_doc
{
    "id": 2,
    "name": "second first"
}

POST /so_test16/_doc
{
    "id": 3,
    "name": "first second third"
}

Запрос

GET /so_test16/_search
{
  "query": {
    "match": {"name": "first second"}
  }
}

и результат

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "so_test16",
        "_type" : "_doc",
        "_id" : "m1KXx2sB4TH56W1hdTF9",
        "_score" : 0.2876821,
        "_source" : {
          "id" : 1,
          "name" : "first second"
        }
      }
    ]
  }
}

Добавление второго решения (если name не тип keyword, а тип text. Здесь нужно добавить fielddata:true для поля name)

Отображения

PUT so_test18
{

    "mappings" : {
      "_doc" : {
        "properties" : {
          "id" : {
            "type" : "long"
          },
          "name" : {
            "type" : "text",
            "fielddata": true
          }
        }
      }

  }
}

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

GET /so_test18/_search
{
  "query": {
    "bool": {
      "must": [
        {"match_phrase": {"name": "first second"}}
      ],
      "filter": {

        "script": {
          "script": {
            "lang": "painless",
            "source": "doc['name'].values.length == 2"
          }
        }

      }
    }

  }
}

и ответ

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.3971361,
    "hits" : [
      {
        "_index" : "so_test18",
        "_type" : "_doc",
        "_id" : "o1JryGsB4TH56W1hhzGT",
        "_score" : 0.3971361,
        "_source" : {
          "id" : 1,
          "name" : "first second"
        }
      }
    ]
  }
}
...