Как запросить точное текстовое поле и отфильтровать термины в другом числовом поле в индексе ElasticSearch?

#amazon-web-services #elasticsearch #lucene #kibana #aws-elasticsearch

Вопрос:

Я пытаюсь запросить индекс для всех документов с соответствующими значениями в определенном текстовом поле Field_Name_1 и отфильтровать эти результаты, чтобы показывать только документы , Field_Name_2 поле которых имеет любое числовое значение в предоставленном списке, [1, 2, 3, 4, 5].

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

Прав ли я, думая, что мне нужно создать новый индекс с Field_Name_1 заданным ключевым словом, а затем переиндексировать? Я раньше не переиндексировался, поэтому беспокоюсь о потере данных, если не сделаю это должным образом. Есть ли способ выполнить этот запрос с Field_Name_1 помощью текстового поля?

Это два запроса, которые я пробовал, но оба они возвращают одни и те же результаты. Единственное различие заключается в том, что первый запрос возвращает «max_score» 9,54, в то время как второй запрос возвращает «max_score» 0.

 GET Index_Name/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "Field_Name_1": "12345-1234-1234-1234-d123f123g123"
        }
      },
      "filter": {
        "terms": {
          "Field_Name_2": [
            1,
            2,
            3,
            4,
            5
          ]
        }
      }
    }
  },
  "track_total_hits": true
}


GET Index_Name/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "match": {
             "Field_Name_1": "12345-1234-1234-1234-d123f123g123"
          }
        },
        {
          "terms": {
            "Field_Name_2": [
              1,
              2,
              3,
              4,
              5
            ]
          }
        }
      ]
    }
  },
  "track_total_hits": true
}
 

Комментарии:

1. Можете ли вы поделиться отображением своего индекса и своей версии ES? curl -X «GET» «локальный хост:9200/yourindex/_mappings»

2. @JuanCarlosAlafita Конечно. Field_Name_1 выглядит так: «идентификатор хранилища» : { «тип» : «текст», «поля» : { «ключевое слово» : { «тип» : «ключевое слово», «ignore_above» : 256 } } } Все отображение индекса слишком велико, чтобы помещать его сюда.

Ответ №1:

Field_Name_1 Поле должно быть keyword типа.

Это связано с тем, что Elasticsearch использует стандартный анализатор, если он не указан. Вы можете проверить токены, сгенерированные с помощью API анализа, как показано ниже —

 GET /_analyze
{
  "analyzer": "standard",
  "text": "12345-1234-1234-1234-d123f123g123"
}
 

Сгенерированные токены будут

 {
  "tokens": [
    {
      "token": "12345",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<NUM>",
      "position": 0
    },
    {
      "token": "1234",
      "start_offset": 6,
      "end_offset": 10,
      "type": "<NUM>",
      "position": 1
    },
    {
      "token": "1234",
      "start_offset": 11,
      "end_offset": 15,
      "type": "<NUM>",
      "position": 2
    },
    {
      "token": "1234",
      "start_offset": 16,
      "end_offset": 20,
      "type": "<NUM>",
      "position": 3
    },
    {
      "token": "d123f123g123",
      "start_offset": 21,
      "end_offset": 33,
      "type": "<ALPHANUM>",
      "position": 4
    }
  ]
}
 

Чтобы вернуть документы, которые Field_Name_1 точно соответствуют значению любого из них, вы можете изменить тип данных Field_Name_1 поля на keyword тип.

Измененное сопоставление индексов будет

 {
  "mappings": {
    "properties": {
      "Field_Name_1": {
        "type": "keyword"
      }
    }
  }
}
 

ИЛИ, если вы явно не определили какое-либо сопоставление, вы также можете изменить свой поисковый запрос следующим образом :

 {
  "query": {
    "bool": {
      "must": {
        "match": {
          "Field_Name_1.keyword": "12345-1234-1234-1234-d123f123g123"   // note this
        }
      },
      "filter": {
        "terms": {
          "Field_Name_2": [
            1,
            2,
            3,
            4,
            5
          ]
        }
      }
    }
  },
  "track_total_hits": true
}
 

При этом будет использоваться keyword анализатор вместо стандартного анализатора (обратите внимание на поле «.ключевое слово» после Field_Name_1 ).

Комментарии:

1. Field_Name_1 был явно определен как текстовое поле, но у меня есть другое поле, которое я определил как текстовое ключевое слово, которое я мог бы использовать вместо Field_Name_1. В противном случае мне пришлось бы переиндексировать данные в новый индекс, который имеет правильный тип для Field_Name_1. Можно ли переиндексировать в новый индекс с тем же именем, не теряя никаких данных? Название индекса имеет значение в моем случае. Есть ли способ получить текущие типы полей, которые я настроил в индексе, чтобы я мог просто изменить те, которые мне нужны при создании новой версии?

2. Если бы я определил свое сопоставление таким образом, как бы я написал ключевое слово и искал его? « ПОМЕСТИТЕ my_index_name/_mapping { «свойства»: { «идентификатор хранилища»: { «тип»: «текст», «поля»: { «ключевое слово»: { «тип»: «ключевое слово», «ignore_above»: 256 } } } } } «

Ответ №2:

Я думаю, что то, что написал ЭСКодер, является ответом на ваш вопрос.

Дополнительно,

«Баллы, рассчитанные для запросов в контексте запроса, представлены в виде чисел с плавающей запятой с одной точностью»

В контексте фильтра баллы не рассчитываются. Контекст фильтра в основном используется для фильтрации структурированных данных, например, установлено ли в поле Field_Name_1 значение «12345-11234-11234-d123f123g123»?

«Часто используемые фильтры будут автоматически кэшироваться Elasticsearch для ускорения производительности».

Если вам требуется точно соответствовать значению Field_Name_1, вы можете использовать фильтры в качестве лучшего варианта.

https://www.elastic.co/guide/en/elasticsearch/reference/7.11/query-filter-context.html

 GET Index_Name/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "match": {
             "Field_Name_1.keyword": "12345-1234-1234-1234-d123f123g123"
          }
        },
        {
          "terms": {
            "Field_Name_2": [
              1,
              2,
              3,
              4,
              5
            ]
          }
        }
      ]
    }
  },
  "track_total_hits": true
}