Search code examples
elasticsearch

How to match nested property without using the nested property in ES


I am building a search functionality for products using ElasticSearch. We need to show relevant results by category, title and brand, depending on what the user has entered into the search box. For example, if you write Apple Laptop, you want to show only Apple Laptops. We don't want to show Apple Watches, Apple iPhones, Lenovo Laptops etc.

The problem is that the function works perfectly if we have category_title. But, category is actually a nested object with title and name properties.

Initial query:

{
    "query": {
        "bool": {
            "must": [
                {
                    "query_string": {
                        "query":  "apple~ AND laptop~",
                        "fields": [
                            "category_title",
                            "title",
                            "brand"
                        ]
                    }
                }
            ]
        }
    }
}

So the query should look like:

{
    "query": {
        "bool": {
            "must": [
                {
                    "query_string": {
                        "query":  "apple~ AND laptop~",
                        "fields": [
                            "category.title",
                            "title",
                            "brand"
                        ]
                    }
                }
            ]
        }
    }
}

How can I keep the same search behaviour and still being able to search by category.title?

Schema:

{
  "mappings": {
    "properties": {
      "brand": {
        "type": "keyword"
      },
      "category": {
        "type": "nested",
        "properties": {
          "name": {
            "type": "keyword"
          },
          "title": {
            "type": "text"
          }
        }
      },
      "name": {
        "type": "keyword"
      },
      "title": {
        "type": "text"
      }
    }
  }
}

Solution

  • EDIT:

    I'm updating my answer and sharing a solution. It's not the best one but can help you.

    Elasticsearch copy_to

    PUT product_stack2
    {
      "mappings": {
        "properties": {
          "brand": {
            "type": "keyword",
            "copy_to": "search_field"
          },
          "category": {
            "type": "nested",
            "properties": {
              "name": {
                "type": "keyword",
                "copy_to": "search_field"
              },
              "title": {
                "type": "text",
                "copy_to": "search_field"
              }
            }
          },
          "name": {
            "type": "keyword",
                "copy_to": "search_field"
          },
          "title": {
            "type": "text",
            "copy_to": "search_field"
          }
        }
      }
    }
    

    PUT product_stack2/_doc/1
    {
      "name": "1",
      "brand": "apple",
      "category": {
        "name": "1",
        "title": "laptops"
      },
      "title": "Macbook Pro"
    }
    

    GET product_stack2/_search
    {
      "query": {
        "bool": {
          "should": [
            {
              "query_string": {
                "query": "apple~ AND laptop~",
                "fields": [
                  "search_field"
                ]
              }
            }
          ]
        }
      }
    }
    

    Result: enter image description here