0

In Elastic Search I have an index named Menu. In Menu have an array of Shop. Something like this.

{
  "menu_id": 1,
  "name": 1,
  "shops": [
    {
      "name": "A",
      "shop_id: "A",
    },
    {
      "name": "B",
      "shop_id: "B",
    }
  ]
}

{
  "menu_id": 2,
  "name": 2,
  "shops": [
    {
      "name": "C",
      "shop_id: "C",
    }
  ]
}

{
  "menu_id": 3,
  "name": 3,
  "shops": [
    {
      "name": "A",
      "shop_id: "A",
    }
  ]
}

{
  "menu_id": 4,
  "name": 4,
  "shops": [
    {
      "name": "A",
      "shop_id: "A",
    },
    {
      "name": "C",
      "shop_id: "C",
    }
  ]
}

With my query I want to search Shop that have id "A" or "C". I want my result being like this.

    {
      "name": "A",
      "shop_id: "A",
    },
    {
      "name": "C",
      "shop_id: "C",
    }

I tried with this query.

{
  "_source": "shops",
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "shops.id": "A"
          }
        },
        {
          "match": {
            "shops.id": "C"
          }
        }
      ]
    }
  },
  "aggs": {
    "all_shops": {
      "terms": {
        "field": "shops.id.keyword",
        "min_doc_count": 1
      },
      "aggs": {
        "real_shop": {
          "top_hits": {
            "_source": [
              "shops"
            ],
            "size": 1
          }
        }
      }
    }
  }
}

And this query.

{
  "_source": "shops",
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "shops.id": "A"
          }
        },
        {
          "match": {
            "shops.id": "C"
          }
        }
      ]
    }
  },
  "aggs": {
    "messages": {
      "filters": {
        "filters": [
          {
            "match": {
              "shops.id": "A"
            }
          },
          {
            "match": {
              "shops.id": "C"
            }
          }
        ]
      },
      "aggs": {
        "real_shop": {
          "top_hits": {
            "_source": [
              "shops"
            ],
            "size": 1
          }
        }
      }
    }
  }
}

I still got many "A", "B" and many "C".

How can I get just once "A" and once "C".

I cannot search it with Index Shop Because I want to use Information from Menu to search it.

Final Query is "Search shop with shop's name or menu's name with shop ids".

1 Answer 1

1

You need to make shops to be of the nested type, to query on each nested field object. You can use inner_hits to return documents that matched exactly with the query. Modify your index mapping as shown below

{
  "mappings": {
    "properties": {
      "shops": {
        "type": "nested"
      }
    }
  }
}

Search Query:

{
  "query": {
    "nested": {
      "path": "shops",
      "query": {
        "terms": {
          "shops.shop_id.keyword": [
            "A",
            "C"
          ]
        }
      },
      "inner_hits": {}
    }
  }
}

Search Result:

"hits": [
      {
        "_index": "66675093",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "menu_id": 1,
          "name": 1,
          "shops": [
            {
              "name": "A",
              "shop_id": "A"
            },
            {
              "name": "B",
              "shop_id": "B"
            }
          ]
        },
        "inner_hits": {
          "shops": {
            "hits": {
              "total": {
                "value": 1,
                "relation": "eq"
              },
              "max_score": 1.0,
              "hits": [
                {
                  "_index": "66675093",
                  "_type": "_doc",
                  "_id": "1",
                  "_nested": {
                    "field": "shops",
                    "offset": 0
                  },
                  "_score": 1.0,
                  "_source": {
                    "name": "A",            // note this
                    "shop_id": "A"
                  }
                }
              ]
            }
          }
        }
      },
      {
        "_index": "66675093",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "menu_id": 1,
          "name": 1,
          "shops": [
            {
              "name": "C",
              "shop_id": "C"
            }
          ]
        },
        "inner_hits": {
          "shops": {
            "hits": {
              "total": {
                "value": 1,
                "relation": "eq"
              },
              "max_score": 1.0,
              "hits": [
                {
                  "_index": "66675093",
                  "_type": "_doc",
                  "_id": "2",
                  "_nested": {
                    "field": "shops",
                    "offset": 0
                  },
                  "_score": 1.0,
                  "_source": {
                    "name": "C",
                    "shop_id": "C"          // note this
                  }
                }
              ]
            }
          }
        }
      }
    ]

UPDATE 1:

You can use filter aggregation along with nested aggregation, to achieve your use case. Try out this below query

{
  "size": 0,
  "aggs": {
    "NAME": {
      "nested": {
        "path": "shops"
      },
      "aggs": {
        "NAME": {
          "filter": {
            "terms": {
              "shops.shop_id.keyword": ["A","C"]
            }
          },
          "aggs": {
            "NAME": {
              "terms": {
                "field": "shops.shop_id.keyword"
              },
              "aggs": {
                "top_sales_hits": {
                  "top_hits": {
                    "size": 1
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Search Result will be

"aggregations": {
    "NAME": {
      "doc_count": 6,
      "NAME": {
        "doc_count": 5,
        "NAME": {
          "doc_count_error_upper_bound": 0,
          "sum_other_doc_count": 0,
          "buckets": [
            {
              "key": "A",
              "doc_count": 3,
              "top_sales_hits": {
                "hits": {
                  "total": {
                    "value": 3,
                    "relation": "eq"
                  },
                  "max_score": 1.0,
                  "hits": [
                    {
                      "_index": "66675093",
                      "_type": "_doc",
                      "_id": "1",
                      "_nested": {
                        "field": "shops",
                        "offset": 0
                      },
                      "_score": 1.0,
                      "_source": {
                        "name": "A",        // note this
                        "shop_id": "A"
                      }
                    }
                  ]
                }
              }
            },
            {
              "key": "C",
              "doc_count": 2,
              "top_sales_hits": {
                "hits": {
                  "total": {
                    "value": 2,
                    "relation": "eq"
                  },
                  "max_score": 1.0,
                  "hits": [
                    {
                      "_index": "66675093",
                      "_type": "_doc",
                      "_id": "2",
                      "_nested": {
                        "field": "shops",
                        "offset": 0
                      },
                      "_score": 1.0,
                      "_source": {
                        "name": "C",      // note this
                        "shop_id": "C"
                      }
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  }
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you so much is work. But how can I get inner hits as a distinct values. because shop A is in many menus.
@Sun please go through the updated part of answer, and let me know if this resolves your issue ?
Thank you so much. you saved a lot of my time. It works.
@Sun glad I could help you 🙂

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.