Elasticsearch - фильтр, где (один из вложенного массива) и (весь вложенный массив)

TL; DR. Как проверить, соответствуют ли одному из и всем вложенным массивом определенные критерии?

У меня есть document. Каждый document имеет массив вложенных outer объектов, которые сами имеют список вложенных объектов inner. Мне нужно выполнить фильтр для всех документов, где соответствует хотя бы один из документов outer вложенных объектов. Когда я говорю совпадение, я имею в виду, что все объекты <вложенные объекты outer outer совпадают. Вот пример отображения для ссылки;

{ "document" : {
    "properties" : {
      "name" : {
        "type" : "string"
      },
      "outer" : {
        "type" : "nested",
        "properties" : {
          "inner" : {
            "type" : "nested",
            "properties" : {
              "match" : {
                "type" : "string",
                "index" : "not_analyzed"
              },
              "type" : {
                "type" : "string",
                "index" : "not_analyzed"
              }
    }}}}}}
}

Если в документе нет объектов outer/inner, считается, что он соответствует. Но для того, чтобы ухудшить положение, внутренние объекты должны рассматриваться как соответствующие друг другу в зависимости от type в виде условной логики (например, CASE в SQL). Например, если type был термином "Country", то объект inner считался бы соответствующим, если match был указанным кодом страны, например ES. Документ может иметь inner объекты переменной type, и нет гарантии, что будут существовать определенные типы.

Исходя из императивного (Java) программирования, у меня возникают невероятные проблемы с тем, как реализовать такую ​​фильтрацию. Ничто, о котором я не могу думать, даже смутно соответствует этому поведению. До сих пор все, что у меня есть, - это отфильтрованный запрос;

"filtered" : {
      "query" : {
        "match_all" : { }
      },
      "filter" : {
        "bool" : {
          "should" : {
            "missing" : {
              "field" : "outer.inner.type"
            }
    }}}}
}

Итак, вопрос в том, что...

Как фильтровать документы, у которых есть хотя бы один outer объект, который имеет все inner объекты, соответствующие на основе type inner объект?

Подробнее по запросу -

Пример документа JSON

{
    "name":"First",
    "outer":[
        {
            "inner":[
                {"match":"ES","type":"Country"},
                {"match":"Elite","type":"Market"}
            ]
        },{
            "inner":[
                {"match":"GBR","type":"Country"},
                {"match":"1st Class","type":"Market"},
                {"match":"Admin","type":"Role"}
            ]
        }
    ],
    "lockVersion":0,"sourceId":"1"
}

Приведенный выше пример должен пройти через фильтр, если мы предоставим "1st Class" market и страну "GRB", потому что второй из двух объектов outer будет считаться совпадением, поскольку оба inner соответствуют объекты. Если бы мы предоставили стране страны "GRB" и на рынке "Elite", то мы бы не вернули этот документ, потому что ни один из объектов outer не беспокоился бы о своих объектах inner в целом. Если бы мы хотели, чтобы второй объект outer соответствовал, то все три inner должны были бы совпадать. Обратите внимание, что в третьем inner есть дополнительный type. Это приводит к ситуации, когда , если существует тип , тогда он должен иметь соответствие для него else, он не должен совпадать, потому что он отсутствует.

Ответ 1

Один из вложенных массивов

Имея один из, вложенный массив, соответствующий некоторым критериям, оказывается очень простым. A вложенный фильтр оценивает соответствие /true, если любой из массивов вложенных объектов соответствует указанным внутренним фильтрам. Например, для массива объектов outer, где один из этих объектов имеет поле match со значением "matching", следующее считается истинным.

"nested": {
   "path": "outer",
   "filter": {
       "term" : { "match" : "matching" } 
   }
}

Вышеупомянутое будет считаться истинным/совпадающим, если один из вложенных объектов outer имеет поле с именем match со значением "matching".

Все вложенные массивы

Наличие вложенного фильтра будет считаться совпадающим, если все более вложенные объекты в сопоставлении массива. На самом деле это невозможно. Но учитывая, что считается совпадением, если только один из вложенных объектов соответствует фильтру, мы можем отменить логику и сказать: "Если none вложенных объектов не соответствует для достижения того, что нам нужно. Например, заданный массив вложенных объектов outer.inner, где все эти объекты имеют поле match со значением "matching", следующее считается истинным.

"not" : {
   "nested": {
      "path": "outer.inner",
      "filter": {
          "not" : {
              "term" : { "match" : "matching" } 
          }
      }
   }
}

Вышеупомянутое будет считаться истинным/сопоставлением, потому что none вложенных outer.inner объектов не (двойной отрицательный) имеет поле с именем match с значение "matching". Это, конечно, такое же, как все вложенные inner объекты, имеющие поле match со значением "matching".

Отсутствие вложенных объектов

Вы не можете проверить, отсутствует ли поле, содержащее вложенные объекты, с помощью традиционного отсутствующего фильтра. Это связано с тем, что вложенные объекты фактически не являются в документе, они хранятся где-то в другом месте. Как таковые отсутствующие фильтры всегда будут считаться истинными. Однако вы можете проверить, что фильтр match_all не возвращает таких результатов;

"not": {
   "nested": {
      "path": "outer",
      "filter": {
          "match_all": {}
       }
    }
 }

Это считается истинным/совпадающим, если match_all не находит результатов.

Ответ 2

Ну, это doozy, но этот запрос, кажется, делает то, что вы хотите:

POST /test_index/_search
{
   "query": {
      "filtered": {
         "filter": {
            "nested": {
               "path": "outer",
               "filter": {
                  "bool": {
                     "must": [
                        {
                           "nested": {
                              "path": "outer.inner",
                              "filter": {
                                 "bool": {
                                    "must": [
                                       { "term": { "outer.inner.type": "Market" } },
                                       { "term": { "outer.inner.match": "1st Class" } }
                                    ]
                                 }
                              }
                           }
                        },
                        {
                           "nested": {
                              "path": "outer.inner",
                              "filter": {
                                 "bool": {
                                    "must": [
                                       { "term": { "outer.inner.type": "Country" } },
                                       { "term": { "outer.inner.match": "GBR" } }
                                    ]
                                 }
                              }
                           }
                        }
                     ]
                  }
               }
            }
         }
      }
   }
}

Вот какой код я использовал для его проверки:

http://sense.qbox.io/gist/f554c2ad2ef2c7e6f5b94b1ddb907813370f4edc

Сообщите мне, если вам нужно объяснение логики; это своего рода участие.