Elasticsearch - Скрипт-фильтр по списку вложенных объектов - PullRequest
4 голосов
/ 05 июля 2019

Я пытаюсь выяснить, как решить эти две проблемы, которые у меня возникают с моим индексом ES 5.6.

"mappings": {
    "my_test": {
        "properties": {
            "Employee": {
                "type": "nested",
                "properties": {
                    "Name": {
                        "type": "keyword",
                        "normalizer": "lowercase_normalizer"
                    },
                    "Surname": {
                        "type": "keyword",
                        "normalizer": "lowercase_normalizer"
                    }
                }
            }
        }
    }
}

Мне нужно создать два отдельных скриптовых фильтра:

1 -Фильтрация документов, размер массива сотрудников которых равен == 3

2 - Фильтрация документов, в которых первый элемент массива имеет "Имя" == "Джон"

Я пытался сначала сделать несколькошаги, но я не могу перебрать список.У меня всегда есть ошибка исключения нулевого указателя.

{
  "bool": {
    "must": {
      "nested": {
        "path": "Employee",
        "query": {
          "bool": {
            "filter": [
              {
                "script": {
                  "script" :     """

                   int array_length = 0; 
                   for(int i = 0; i < params._source['Employee'].length; i++) 
                   {                              
                    array_length +=1; 
                   } 
                   if(array_length == 3)
                   {
                     return true
                   } else 
                   {
                     return false
                   }

                     """
                }
              }
            ]
          }
        }
      }
    }
  }
}

Ответы [ 2 ]

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

Как заметил Вэл, вы не можете получить доступ к _source документам в запросах скрипта в последних версиях Elasticsearch.Ноasticsearch позволяет вам получить доступ к этому _source в «контексте контекста».

Таким образом, возможный обходной путь (но вы должны быть осторожны с производительностью) - это использовать в своем запросе счетную оценку в сочетании с min_score.

Вы можете найти пример такого поведения в этой публикации переполнения стека Запросить документы по сумме значений вложенных полей вasticsearch .

В вашем случае такой запрос можетвыполните задание:

POST <your_index>/_search
{
  "min_score": 0.1,
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "source": """
              if (params["_source"]["Employee"].length === params.nbEmployee) {
                def firstEmployee = params._source["Employee"].get(0);
                if (firstEmployee.Name == params.name) {
                  return 1;
                } else {
                  return 0;
                }
              } else {
                return 0;
              }
""",
              "params": {
                "nbEmployee": 3,
                "name": "John"
              }
            }
          }
        }
      ]
    }
  }
}

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

Но помните, что это может быть очень тяжелым для вашего кластера, как уже упоминал Val.Вы должны сузить набор документов, к которым вы будете применять скрипт, добавив фильтры в function_score query (match_all в моем примере).И в любом случае это не тот способ, которым следует использовать Elasticsearch, и вы не можете ожидать ярких результатов при таком взломанном запросе.

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

1 - Фильтровать документы, у которых размер массива сотрудников равен == 3

Для первой проблемы лучше всего добавить еще одно поле корневого уровня (например, NbEmployees), который содержит количество элементов в массиве Employee, так что вы можете использовать запрос range, а не дорогой запрос script.

Затем при каждом изменении массива EmployeeВы также обновляете это поле NbEmployees соответственно.Гораздо эффективнее!

2 - Фильтровать документы, у которых первый элемент массива имеет «Имя» == «Джон»

Что касается этого, вам нужно знатьчто вложенные поля являются отдельными (скрытыми) документами в Lucene, поэтому невозможно получить доступ ко всем вложенным документам одновременно в одном запросе.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...