2015-05-25 2 views
0

Скажем, у меня был этот документ:Фильтр массив словарей, что все должно содержать все указанные значения

  { 
     "_index": "food", 
     "_type": "recipes", 
     "_id": "AU2LjsMLOuShTUj_LBrT", 
     "_score": 1, 
     "_source": { 
      "name": "granola bars", 
      "ingredients": [ 
       { 
       "name": "butter", 
       "quantity": 4 
       }, 
       { 
       "name": "granola", 
       "quantity": 6 
       } 
       ] 
      } 
     } 

Используя следующий фильтр соответствует этот документ штраф:

POST /food/recipes/_search 
{ 
"query": { 
    "filtered": { 
     "query": { 
      "match_all": { } 
     }, 
     "filter": { 
      "nested": { 
       "path": "ingredients", 
       "filter": { 
        "bool": { 
         "must": [ 
          { 
           "terms": { 
            "ingredients.name": [ 
             "butter", 
             "granola" 
            ] 
           } 
          } 
         ] 
        } 
       } 
      } 
     } 
    } 
} 
} 

Однако он также будет соответствовать документы, содержащие дополнительные ингредиенты.
Как я могу запросить, чтобы он соответствовал только документам, в которых есть только ингредиенты с маслом и гранолой?

ответ

1

Вам нужен «двойной отрицательный», если можно так выразиться. Вы хотите сопоставить родительские документы с вложенными документами, соответствующими вашему запросу, и никакие вложенные документы, которые не соответствуют вашему запросу.

Для тестирования я создал следующий индекс:

PUT /test_index 
{ 
    "settings": { 
     "number_of_shards": 1 
    }, 
    "mappings": { 
     "doc": { 
     "properties": { 
      "ingredients": { 
       "type": "nested", 
       "properties": { 
        "name": { 
        "type": "string" 
        }, 
        "quantity": { 
        "type": "long" 
        } 
       } 
      }, 
      "name": { 
       "type": "string" 
      } 
     } 
     } 
    } 
} 

И добавил эти два документа:

PUT /test_index/doc/1 
{ 
    "name": "granola bars", 
    "ingredients": [ 
     { 
     "name": "butter", 
     "quantity": 4 
     }, 
     { 
     "name": "granola", 
     "quantity": 6 
     } 
    ] 
} 

PUT /test_index/doc/2 
{ 
    "name": "granola cookies", 
    "ingredients": [ 
     { 
     "name": "butter", 
     "quantity": 5 
     }, 
     { 
     "name": "granola", 
     "quantity": 7 
     }, 
     { 
     "name": "milk", 
     "quantity": 2 
     }, 
     { 
     "name": "sugar", 
     "quantity": 7 
     } 
    ] 
} 

Ваш запрос возвращает оба документа. Для целей этого вопроса, чтобы было легче понять, я первый упрощена запрос немного:

POST /test_index/doc/_search 
{ 
    "query": { 
     "filtered": { 
     "query": { 
      "match_all": {} 
     }, 
     "filter": { 
      "nested": { 
       "path": "ingredients", 
       "filter": { 
        "terms": { 
        "ingredients.name": [ 
         "butter", 
         "granola" 
        ] 
        } 
       } 
      } 
     } 
     } 
    } 
} 

Затем я добавил внешний "bool" с двумя "nested" фильтрами. Одним из них является фильтром вы изначально были внутри "must", а вторая противоположна фильтра вы имели (так он будет соответствовать вложенным документам, которые не содержат эти термины), внутри "must_not":

POST /test_index/doc/_search 
{ 
    "query": { 
     "filtered": { 
     "query": { 
      "match_all": {} 
     }, 
     "filter": { 
      "bool": { 
       "must": [ 
        { 
        "nested": { 
         "path": "ingredients", 
         "filter": { 
          "terms": { 
           "ingredients.name": [ 
           "butter", 
           "granola" 
           ] 
          } 
         } 
        } 
        } 
       ], 
       "must_not": [ 
        { 
        "nested": { 
         "path": "ingredients", 
         "filter": { 
          "not": { 
           "filter": { 
           "terms": { 
            "ingredients.name": [ 
             "butter", 
             "granola" 
            ] 
           } 
           } 
          } 
         } 
        } 
        } 
       ] 
      } 
     } 
     } 
    } 
} 

Это возвращает только один документ:

{ 
    "took": 1, 
    "timed_out": false, 
    "_shards": { 
     "total": 1, 
     "successful": 1, 
     "failed": 0 
    }, 
    "hits": { 
     "total": 1, 
     "max_score": 1, 
     "hits": [ 
     { 
      "_index": "test_index", 
      "_type": "doc", 
      "_id": "1", 
      "_score": 1, 
      "_source": { 
       "name": "granola bars", 
       "ingredients": [ 
        { 
        "name": "butter", 
        "quantity": 4 
        }, 
        { 
        "name": "granola", 
        "quantity": 6 
        } 
       ] 
      } 
     } 
     ] 
    } 
} 

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

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

+0

это так кажется очевидно, сейчас, спасибо! – user3414879

Смежные вопросы