Подтвердить что ты не робот

Фильтрация elasticsearch по размеру поля, которое является массивом

Как я могу фильтровать документы, у которых есть поле, которое является массивом, и имеет более N элементов?

Как я могу фильтровать документы, у которых есть поле, которое является пустым массивом?

Является ли грани решением? Если да, то как?

4b9b3361

Ответ 1

Я бы посмотрел на script фильтр. Следующий фильтр должен возвращать только документы, в которых есть не менее 10 элементов в поле fieldname, которое представляет собой массив. Имейте в виду, что это может быть дорогостоящим в зависимости от того, сколько документов у вас есть в вашем индексе.

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > 10"
    }
}

Относительно второго вопроса: у вас действительно есть пустой массив? Или это просто поле массива без значения? Вы можете использовать отсутствующий фильтр для получения документов, которые не имеют значения для определенного поля:

"filter" : {
    "missing" : { "field" : "user" }
}

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

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > param1"
        "params" : {
            "param1" : 10
        }
    }
}

Ответ 2

Ответ javanna верен на Elasticsearch 1.3.x и более ранних версиях, так как 1.4 модуль сценариев по умолчанию изменился на groovy (был mvel).

Чтобы ответить на вопрос OP.

В Elasticsearch 1.3.x и ранее используйте этот код:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > 10"
    }
}

В Elasticsearch 1.4.x и более поздних версиях используйте этот код:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.size() > 10"
    }
}

Кроме того, на Elasticsearch 1.4.3 и более поздних версиях вам необходимо включить динамический скриптинг, поскольку он по умолчанию отключен из-за проблемы с безопасностью. См.: https://www.elastic.co/guide/en/elasticsearch/reference/1.4/modules-scripting.html

Ответ 3

Imho правильный способ фильтрации массивов по размеру с использованием сценариев:

"filter" : {
    "script" : {
        "script" : "_source.fieldName.size() > 1"
    }
}

Если я это сделаю, как @javanna предлагает исключение groovy.lang.MissingPropertyException: No such property: length for class: java.lang.String

Ответ 4

Все еще отправляю сюда для того, кто застрял в той же ситуации со мной. Допустим, ваши данные выглядят так:

{
    "_source": {
        "fieldName" : [
            {
                "f1": "value 11",
                "f2": "value 21"
            },
            {
                "f1": "value 12",
                "f2": "value 22"
            }
        ]
    }
}

Затем отфильтровать fieldName с длиной> 1, например:

"query": {
    "bool" : {
        "must" : {
            "script" : {
                "script" : {
                    "inline": "doc['fieldName.f1'].values.length > 1",
                    "lang": "painless"
                 }
            }
        }
    }
}

Синтаксис сценария приведен в виде документации по ES 5.4 https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-query.html.

Ответ 6

Самый простой способ сделать это - "денормализовать" ваши данные, чтобы у вас было свойство, которое содержит счетчик и логическое, если оно существует или нет. Затем вы можете просто выполнить поиск по этим свойствам.

Например:

{
   "id": 31939,
   "hasAttachments": true,
   "attachmentCount": 2,
   "attachments": [
      {
         "type": "Attachment",
         "name": "txt.txt",
         "mimeType": "text/plain"
      },
      {
         "type": "Inline",
         "name": "jpg.jpg",
         "mimeType": "image/jpeg"
      }
   ]  
}

Ответ 7

Когда вам нужно найти документы, которые содержат какое-то поле, размер/длина которого должен быть больше нуля, @javanna дала правильный ответ. Я только хотел добавить, если ваше поле является текстовым полем, и вы хотите найти документы, которые содержат некоторый текст в этом поле, вы не можете использовать тот же запрос. Вам нужно будет сделать что-то вроде этого:

GET index/_search 
{
    "query": {
        "bool": {
            "must": [
                {
                    "range": {
                        "FIELD_NAME": {
                            "gt": 0
                        }
                    }
                }
            ]
        }
    }
}

Это не точный ответ на этот вопрос, потому что ответ уже существует, но решение для аналогичной проблемы, которое у меня было, так что, возможно, кто-то найдет его полезным.

Ответ 8

Если у вас есть массив объектов, которые не сопоставлены с nested, имейте в виду, что Elastic упростит их в:

attachments: [{size: 123}, {size: 456}] --> attachments.size: [123, 456]

Итак, вы хотите сослаться на свое поле как doc['attachments.size'].length, а не doc['attachments'].length, что очень нелогично.

То же самое для doc.containsKey(attachments.size).

Часть .values устарела и больше не нужна.