Home > Enterprise >  Elastic search terms aggregation for getting filter options
Elastic search terms aggregation for getting filter options

Time:12-01

im trying to implement product searching and want to get search results along with filters to filter from. i have managed to get the filter keys reference, but also want values of those keys

my product body is

 {
      ...product,
       "attributes": [
            {
              "name": "Color",
              "value": "Aqua Blue"
            },
            {
              "name": "Gender",
              "value": "Female"
            },
            {
              "name": "Occasion",
              "value": "Active Wear"
            },
            {
              "name": "Size",
              "value": "0"
            }
          ],
 }

and im using the this query in es

GET product/_search
{
  "aggs": {
    "filters": {
      "terms": {
        "field": "attributes.name"
      
      },
      "aggs": {
        "values": {
          "terms": {
            "field": "attributes.value",
            "size": 10
          }
        }
      }
    }
    
  }
}

Not sure why, but im getting all values for each key

 "aggregations": {
    "filters": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Color",
          "doc_count": 3,
          "values": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "Active Wear",
                "doc_count": 3
              },
              {
                "key": "Aqua Blue",
                "doc_count": 3
              },
              {
                "key": "Female",
                "doc_count": 3
              },
              {
                "key": "0",
                "doc_count": 2
              },
              {
                "key": "10XL",
                "doc_count": 1
              }
            ]
          }
        },
        {
          "key": "Gender",
          "doc_count": 3,
          "values": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "Active Wear",
                "doc_count": 3
              },
              {
                "key": "Aqua Blue",
                "doc_count": 3
              },
              {
                "key": "Female",
                "doc_count": 3
              },
              {
                "key": "0",
                "doc_count": 2
              },
              {
                "key": "10XL",
                "doc_count": 1
              }
            ]
          }
        },
        {
          "key": "Occasion",
          "doc_count": 3,
          "values": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "Active Wear",
                "doc_count": 3
              },
              {
                "key": "Aqua Blue",
                "doc_count": 3
              },
              {
                "key": "Female",
                "doc_count": 3
              },
              {
                "key": "0",
                "doc_count": 2
              },
              {
                "key": "10XL",
                "doc_count": 1
              }
            ]
          }
        },
        {
          "key": "Size",
          "doc_count": 3,
          "values": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "Active Wear",
                "doc_count": 3
              },
              {
                "key": "Aqua Blue",
                "doc_count": 3
              },
              {
                "key": "Female",
                "doc_count": 3
              },
              {
                "key": "0",
                "doc_count": 2
              },
              {
                "key": "10XL",
                "doc_count": 1
              }
            ]
          }
        }
      ]
    }

Also i do not want to specify manually all keys explicitly like Color, Size to get their respective values each. Thanks :)

CodePudding user response:

To keep things simple must you use a single field to store attributes:

"gender":"Male"

I assume you have tons of attributes so you create an array instead, to handle that you will have to use "nested" field type.

Nested type preserves the relation between each of the nested document properties. If you dont use nested you will see all the properties and values mixed and you will not be able to aggregate by a property without manually adding filters.

You can read an article I wrote about that here:

https://opster.com/guides/elasticsearch/data-architecture/elasticsearch-nested-field-object-field/

Mappings :

PUT test_product_nested
{
  "mappings": {
    "properties": {
      "attributes": {
        "type": "nested",
        "properties": {
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "value": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      },
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

This query will only show Red products of size XL and aggregate by attributes.

If you want to do OR's instead of AND's you must use "should" clauses instead of "filter" clauses.

Query

POST test_product_nested/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "nested": {
            "path": "attributes",
            "query": {
              "bool": {
                "filter": [
                  {
                    "term": {
                      "attributes.name.keyword": "Color"
                    }
                  },
                  {
                    "term": {
                      "attributes.value.keyword": "Red"
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "attributes",
            "query": {
              "bool": {
                "filter": [
                  {
                    "term": {
                      "attributes.name.keyword": "Size"
                    }
                  },
                  {
                    "term": {
                      "attributes.value.keyword": "XL"
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  },
  "aggs": {
    "attributes": {
      "nested": {
        "path": "attributes"
      },
      "aggs": {
        "name": {
          "terms": {
            "field": "attributes.name.keyword"
          },
          "aggs": {
            "values": {
              "terms": {
                "field": "attributes.value.keyword",
                "size": 10
              }
            }
          }
        }
      }
    }
  }
}

Results

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0,
    "hits": [
      {
        "_index": "test_product_nested",
        "_id": "aJRayoQBtNG1OrZoEOQi",
        "_score": 0,
        "_source": {
          "title": "Product 1",
          "attributes": [
            {
              "name": "Color",
              "value": "Red"
            },
            {
              "name": "Gender",
              "value": "Female"
            },
            {
              "name": "Occasion",
              "value": "Active Wear"
            },
            {
              "name": "Size",
              "value": "XL"
            }
          ]
        }
      }
    ]
  },
  "aggregations": {
    "attributes": {
      "doc_count": 4,
      "name": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": "Color",
            "doc_count": 1,
            "values": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "Red",
                  "doc_count": 1
                }
              ]
            }
          },
          {
            "key": "Gender",
            "doc_count": 1,
            "values": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "Female",
                  "doc_count": 1
                }
              ]
            }
          },
          {
            "key": "Occasion",
            "doc_count": 1,
            "values": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "Active Wear",
                  "doc_count": 1
                }
              ]
            }
          },
          {
            "key": "Size",
            "doc_count": 1,
            "values": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "XL",
                  "doc_count": 1
                }
              ]
            }
          }
        ]
      }
    }
  }
}
  • Related