Как я могу найти все документы в elasticsearch, которые содержат число в определенном поле?

У меня есть поле типа keyword, которое может содержать либо число, либо строку. Если поле не содержит букв, я хотел бы нажать на этот документ. Как я могу это сделать?

Мое отображение индекса выглядит так:

{
  "mappings": {
    "Entry": {
      "properties": {
        "testField": {
          "type": "keyword"
        }
      }
    }
  }
}

Мои документы выглядят так:

{
  "testField":"123abc"
}

или

{
  "testField": "456789"
}

Я пробовал запрос:

{
  "query": {
    "range": {
      "gte": 0,
      "lte": 2000000
    }
  }
}

но он по-прежнему актуален 123abc. Как я могу спроектировать это так, чтобы я попадал только в документы с номером в этом конкретном поле?

0
0
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Afaik, у Elasticsearch нет прямого решения для этого.

Вместо этого вам нужно будет написать Запрос сценария. Ниже то, что вы ищете:

POST <your_index_name>/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "script": {
            "script": {
              "lang": "painless", 
              "source": """
                  try{           
                    String temp = doc['testField'].value;
                    int a = Integer.parseInt(temp);
                    if (a instanceof Integer)
                      return true;
                  }catch(NumberFormatException e){
                    return false;
                  }
              """
            }
          }
        }
      ]
    }
  }
}

Надеюсь, поможет!

Ответ принят как подходящий

Есть еще один более оптимальный вариант для достижения именно того, чего вы хотите. Вы можете использовать прием конвейеров API, а с помощью script процессор вы можете создать еще одно числовое поле во время индексации, которое затем можно будет использовать более эффективно во время поиска.

Приведенный ниже конвейер загрузки содержит один процессор script, который создаст другое поле с именем numField, которое будет содержать только числовые значения.

POST _ingest/pipeline/_simulate
{
  "pipeline": {
    "processors": [
      {
        "script": {
          "source": """
          ctx.numField = /\D/.matcher(ctx.testField).replaceAll("");
          """
        }
      }
    ]
  },
  "docs": [
    {
      "_source": {
        "testField": "123"
      }
    },
    {
      "_source": {
        "testField": "abc123"
      }
    },
    {
      "_source": {
        "testField": "123abc"
      }
    },
    {
      "_source": {
        "testField": "abc"
      }
    }
  ]
}

Моделирование этого конвейера с 4 различными документами, имеющими сочетание буквенно-цифрового содержимого, даст следующее:

{
  "docs" : [
    {
      "doc" : {
        "_index" : "_index",
        "_type" : "_type",
        "_id" : "_id",
        "_source" : {
          "numField" : "123",
          "testField" : "123"
        },
        "_ingest" : {
          "timestamp" : "2019-05-09T04:14:51.448Z"
        }
      }
    },
    {
      "doc" : {
        "_index" : "_index",
        "_type" : "_type",
        "_id" : "_id",
        "_source" : {
          "numField" : "123",
          "testField" : "abc123"
        },
        "_ingest" : {
          "timestamp" : "2019-05-09T04:14:51.448Z"
        }
      }
    },
    {
      "doc" : {
        "_index" : "_index",
        "_type" : "_type",
        "_id" : "_id",
        "_source" : {
          "numField" : "123",
          "testField" : "123abc"
        },
        "_ingest" : {
          "timestamp" : "2019-05-09T04:14:51.448Z"
        }
      }
    },
    {
      "doc" : {
        "_index" : "_index",
        "_type" : "_type",
        "_id" : "_id",
        "_source" : {
          "numField" : "",
          "testField" : "abc"
        },
        "_ingest" : {
          "timestamp" : "2019-05-09T04:14:51.448Z"
        }
      }
    }
  ]
}

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

{
  "query": {
    "range": {
      "numField": {
        "gte": 0,
        "lte": 2000000
      }
    }
  }
}

Другие вопросы по теме