Tyler
Tyler

Reputation: 11509

Filtering by bool and has_child with elasticsearch

I have a query in elasticsearch that works just fine:

body =
  size: opts.size
  query:          
    fuzzy_like_this:
    fields: ['title', 'content']
      like_text: opts.search
      fuzziness: 1
  filter:
    has_child:
      type: 'sku'
      filter:
        bool:
          must:
            range:
              regular_price:
                gte: opts.min_price
                lte: opts.max_price
  highlight:
    pre_tags: ['<strong>']
    post_tags: ['</strong>']
    fields:
      title:
        force_source: true
        fragment_size: 150
        number_of_fragments: 1

This gets products whose title or content fuzzy match opts.search and that have skus with the specified price range. It works.

I'd now like to additionally exclude any products that have the hide_from_catalog boolean set to true. However making the small change doesn't work as I expect:

body =
  size: opts.size
  query:          
    fuzzy_like_this:
    fields: ['title', 'content']
      like_text: opts.search
      fuzziness: 1
  filter:
    ### Adding this causes an error ###
    bool:                        
      must_not:                  
        term:                    
          hide_from_catalog: true
    has_child:
      type: 'sku'
      filter:
        bool:
          must:
            range:
              regular_price:
                gte: opts.min_price
                lte: opts.max_price
  highlight:
    pre_tags: ['<strong>']
    post_tags: ['</strong>']
    fields:
      title:
        force_source: true
        fragment_size: 150
        number_of_fragments: 1

I've played around a little and can't seem to get it working. The failure looks like so:

SearchPhaseExecutionException[Failed to execute phase [query_fetch],... 
ElasticsearchParseException[Expected field name but got START_OBJECT \"has_child\"]

Which I assume is because the filtering is formatted incorrectly.

What would be the right way to add this additional filter?

Upvotes: 1

Views: 1814

Answers (1)

Val
Val

Reputation: 217294

You need to include the has_child filter into the bool filter within a must clause, like this:

body =
  size: opts.size
  query:          
    fuzzy_like_this:
    fields: ['title', 'content']
      like_text: opts.search
      fuzziness: 1
  filter:
    bool:                        
      must_not:                  
        term:                    
          hide_from_catalog: true
      must:                  
        has_child:
          type: 'sku'
          filter:
            bool:
              must:
                range:
                  regular_price:
                    gte: opts.min_price
                    lte: opts.max_price
  highlight:
    pre_tags: ['<strong>']
    post_tags: ['</strong>']
    fields:
      title:
        force_source: true
        fragment_size: 150
        number_of_fragments: 1

Upvotes: 3

Related Questions