0

I have data of the form

{
       "Name": "Bolognaise, tomato, olive and feta tart"            
"Prep Time": 20, 
          "Cook Time": 25,       
"Servings": 4,
 "Ingredients": [
              {
                 "name": "puff pastry",
                 "id": 17,
                 "weight": 100
              },
              {                 "name": "bolognaise",
                 "id": 18,
                 "weight": 150
              },
          {
                 "name": "tomatoes",
                 "id": 19,
                 "weight": 200
              },
              {
                 "name": "olives",
                 "id": 20,
                 "weight": 300
              },
              {
                 "name": "cheese",
                 "id": 21,
                 "weight": 230
              },
              {
                 "name": "baby rocket",
                 "id": 22,
                 "weight": 400
              }
           ],
           "Views": 0,
           "Urls": "xcd.com",
           "Tags": [
              "Tomato",
              "Lunch"
           ],
           "Main_ingredient": {
              "type": "Tomato",
              "id": 101,
              "weight": 500
           }
        }
     },

And I am using this query

 {
  "query": {
    "bool": {
      "must": [
        { "match": { "Main_ingredient.type": "Tomato" }}, 
        {"range":{"Main_ingredient.weight":{"lte":1000}}},
        {
          "nested": {
            "path": "Ingredients", 
            "query": {
              "bool": {
                "must": [ 
                  { "match": { "Ingredients.name": "cheese" }},
                  { "range": { "Ingredients.weight":{"lte":400}     }},
                  { "match": { "Ingredients.name": "olives" }},
                  { "range": { "Ingredients.weight":{"lte":400}     }}
                ]
        }}}}
      ]
}}}

I want to change the query so that If I pass the weight and the main ingredient ,then it should return me the ids with the same main ingredient and weight of the main ingredient less than the passed weight . Right now it returns null

user459
  • 111
  • 8

2 Answers2

1

So if I understand your question correctly, you are looking for a term match on Main_ingredients.type AND a less than range on weight. And then you multiple of these "AND" filters. Since you have a mapping that analyzes the Main_ingredient.type field and the Ingredients.name field, you must provide the lowercase values for those strings. Might be better to just change the mapping to not analyze those fields. I think you are looking for something like below. You'll obviously want to add any additional "and" filter filter blocks for additional ingredients that you want to match on.

GET rec/_search
{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "and": {
                "filters": [
                  {
                    "term": {
                      "main_ingredient.type": "tomato"
                    }
                  },
                  {
                    "range": {
                      "main_ingredient.weight": {
                        "lt": 1000
                      }
                    }
                  }
                ]
              }
            },
            {
              "and": {
                "filters": [
                  {
                    "term": {
                      "ingredients.name": "tomatoes"
                    }
                  },
                  {
                    "range": {
                      "ingredients.weight": {
                        "lt": 300
                      }
                    }
                  }
                ]
              }
            }
          ],
          "_cache": true
        }
      }
    }
  }
}
hubbardr
  • 3,153
  • 1
  • 21
  • 27
  • I want to make a query such the (Main Ingredient with name Tomato and with weight less than 1000 ) and (Ingredient with name tomatoes with weight less than 300) Olives with weight less than 400 && Cheese with weight less than 250 . This should return all the recipes which follow these conditions – user459 Jul 07 '15 at 05:50
  • {"final":{"mappings":{"superb":{"properties":{"Cook Time":{"type":"long"},"Ingredients":{"type":"nested","properties":{"id":{"type":"short"},"name":{"type":"string"},"type":{"type":"string"},"weight":{"type":"short"}}},"Main_ingredient":{"properties":{"id":{"type":"long"},"type":{"type":"string"},"weight":{"type":"long"}}},"Name":{"type":"string"},"Prep Time":{"type":"long"},"Servings":{"type":"long"},"Tags":{"type":"string"},"Urls":{"type":"string"},"Views":{"type":"long"}}}}}} – user459 Jul 07 '15 at 14:10
  • Ah. let me edit the query. One note on the mapping...the query will be case sensitive since you are analyzing the Main_ingredients.name. You will always have to provide the lowercase exact value; if the document Main_ingredient.name was "Cheese", you would have to filter on "cheese" since its analyzed. You might consider adding a raw field if you want to do an exact match. See https://www.elastic.co/guide/en/elasticsearch/guide/current/sorting-collations.html#case-insensitive-sorting – hubbardr Jul 07 '15 at 15:46
  • http://stackoverflow.com/a/31271209/4964020 In The above answer it will not work because we can do it through only nested query or nested filter."And" filter does not works here and returns null.And for the case sensitivity replace "term" with "match" then it will work fine . – user459 Jul 07 '15 at 17:34
  • sry I didnt see the nested mapping. – hubbardr Jul 07 '15 at 18:56
0

If you want to require two ingridients like in the example, I believe you have to split them into two nested conditions within your bool - must:

{
  "query": {
    "bool": {
      "must": [
        { "match": { "Main_ingredient.type": "tomato" } },
        { "range": { "Main_ingredient.weight": { "lte": 1000 } } },
        {
          "nested": {
            "path": "Ingredients",
            "query": {
              "bool": {
                "must": [
                  { "match": { "Ingredients.name": "cheese" } },
                  { "range": { "Ingredients.weight": { "lte": 300 } } }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "Ingredients",
            "query": {
              "bool": {
                "must": [
                  { "match": { "Ingredients.name": "olives" } },
                  { "range": { "Ingredients.weight": { "lte": 400 } } }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

which would give you main type = tomato/lte 1000, AND ingridient cheese/lte 300 AND ingridient olives/lte 400.

Peter
  • 106
  • 6