10

I'm pretty new to ES and have been trying to implement faceted navigation in the same way most of the large e-commerce stores do.

Part of my products mapping looks like this:

'name' => [
    'type' => 'string',
    'analyzer' => 'english_analyzer',
],
'range' => [
    'type' => 'string',
    'analyzer' => 'english_analyzer',
],
'filters' => [
    'type' => 'nested',
    'properties' => [
        'name' => [
            'type' => 'string',
            'index' => 'not_analyzed',
        ],
        'values' => [
            'type' => 'object',
            'properties' => [
                'name' => [
                    'type' => 'string',
                    'index' => 'not_analyzed',
                ]
            ]
        ]
    ]
],

As you can see I'm storing the facets in "filters" as a nested object.

In my search query I can then add this aggregation to my query:

'aggs' => [
    'facets' => [
        'nested' => ['path' => 'filters'],
        'aggs' => [
            'filters' => [
                'terms' => [
                    'field' => 'filters.name', //facet group name
                    'size' => 0
                ],
                'aggs' => [
                    'id' => [
                        'terms' => [
                            'field' => 'filters.id' //facet group ID
                        ]
                    ],
                    'values' => [
                        'terms' => [
                            'field' => 'filters.values.name', //facet name
                            'size' => 0
                        ],
                        'aggs' => [
                            'id' => [
                                'terms' => [
                                    'field' => 'filters.values.id' //facet id
                                ]
                            ]
                        ]
                    ]
                ]
            ]
        ]
    ]
]

This gives me a nice list of facets to stick in my navigation. I can apply selected facets to my document results in 2 ways: Using the "post filter" or the "filtered query"

The post filter applies the aggregations after the query and so gives me document counts regardless of what facets have been selected by the user. In contrast the filtered query calculates facet counts based on selected facets, however it hides facets with no matching documents.

What I need to do - and what most of the big e-commerce stores do - is a hybrid of the 2. I want the facet counts to be based on what is selected but ignore any facets within the same group.

If I have these facets:

Colours:

  • Red (1)
  • Blue (2)
  • Green (3)

Brands:

  • Audi (1)
  • Ford (2)
  • BMW (3)

If somebody selects Blue, the counts should remain the same for Red and Green but would effect the counts for brand.

I have found a similar question on Stack Overflow: ElasticSearch aggregation: exclude one filter per aggregation

From what I can gather I need to provide a pre defined list of facets (from my relational DB) and add them to my aggregations. So I have a manual list of my facet groups, then I add a filter bucket (https://www.elastic.co/guide/en/elasticsearch/guide/current/_filter_bucket.html) to each of these. Within the filter, I need to add a bool query which contains all the user selected facets which I include for each facet group, leaving out any facets which belong to that group.

So now I have a huge list of aggregations, grouped/bucketed by their facet group, each of these has a filter containing a bool query which may have a dozen selected fields. The query now is so large it probably would not fit on one page if I posted it here!

This to me just seems like a crazy addition to my query considering what I had to do before was almost what I needed. Is this the ONLY way I can achieve this?

Any help is greatly appreciated, I hope my question is clear enough.

Community
  • 1
  • 1
user3653478
  • 101
  • 3

0 Answers0