У меня есть поле типа keyword
, которое может содержать либо число, либо строку. Если поле не содержит букв, я хотел бы нажать на этот документ. Как я могу это сделать?
Мое отображение индекса выглядит так:
{
"mappings": {
"Entry": {
"properties": {
"testField": {
"type": "keyword"
}
}
}
}
}
Мои документы выглядят так:
{
"testField":"123abc"
}
или
{
"testField": "456789"
}
Я пробовал запрос:
{
"query": {
"range": {
"gte": 0,
"lte": 2000000
}
}
}
но он по-прежнему актуален 123abc
. Как я могу спроектировать это так, чтобы я попадал только в документы с номером в этом конкретном поле?
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
}
}
}
}