Facet Troubles with Elasticsearch on Query

2019-04-01 18:42发布

问题:

When adding a term to my query instead of a filter I am getting 0 facets. FYI I am using the tire gem with Ruby.

Here is my model code with its mapping:

class Property < ActiveRecord::Base
  include Tire::Model::Search
  include Tire::Model::Callbacks

  has_and_belongs_to_many :tags

   mapping do
    indexes :id,                type: 'integer'
    indexes :status
    indexes :refno,             type: 'integer'
    indexes :name,              :analyzer => 'snowball', :boost => 100
    indexes :description
    indexes :tags,              type: 'object',
                                  properties: {
                                    name: { type: 'multi_field',
                                      fields: {
                                        name: { type: 'string', analyzer: 'snowball' },
                                        exact: { type: 'string', index: 'not_analyzed' }
                                      }
                                    }
                                   }                                 
  end

  def to_indexed_json
    to_json( include: { 
      tags: { only: [:name] },
     })
  end

Then here is the search method

  def self.search(params={})
    tire.search(page: params[:page], per_page: 2, load: true) do
      query do
        boolean do
         must { string params[:name], default_operator: "AND" } if params[:name].present?
         must { term :status, 'live' }
         must { term :refno, params[:refno]} if params[:refno].present?
         # must { term :tag, params[:tag]} if params[:tag].present? ## does not work either
         must { term 'tags.name.exact', params[:tag]} if params[:tag].present?
        end
      end
      facet "tags" do
        terms 'tags.name.exact'
      end
      raise to_json
      # raise to_curl
    end
  end

I get 0 Facets. But if I move facets to a filter ie below I get full facets.

  def self.search(params={})
    tire.search(page: params[:page], per_page: 2, load: true) do
      query do
        boolean do
         must { string params[:name], default_operator: "AND" } if params[:name].present?
         must { term :status, 'live' }
         must { term :refno, params[:refno]} if params[:refno].present?
        end
      end
      filter :term, 'tags.name.exact' => params[:tag] if params[:tag].present?
      facet "tags" do
        terms 'tags.name.exact'
      end
      raise to_json
      # raise to_curl
    end
  end

While this is ok it's not want, When a facet filter is clicked I want to remove non available tags from my facet filter and update the new facet count.

If it helps here is the json for the query which works and does not.

## No Factes
{
   "query":{
      "bool":{
         "must":[
            {
               "query_string":{
                  "query":"England",
                  "default_operator":"AND"
               }
            },
            {
               "term":{
                  "status":"live"
               }
            },
            {
               "term":{
                  "tags.name.exact":[
                     "Pet Friendly"
                  ]
               }
            }
         ]
      }
   },
   "facets":{
      "tags":{
         "terms":{
            "field":"tags.name.exact",
            "size":10,
            "all_terms":false
         }
      }
   },
   "size":2
}

## Facets working
{
   "query":{
      "bool":{
         "must":[
            {
               "query_string":{
                  "query":"England",
                  "default_operator":"AND"
               }
            },
            {
               "term":{
                  "status":"live"
               }
            }
         ]
      }
   },
   "facets":{
      "tags":{
         "terms":{
            "field":"tags.name.exact",
            "size":10,
            "all_terms":false
         }
      }
   },
   "filter":{
      "term":{
         "tags.name.exact":[
            "Pet Friendly"
         ]
      }
   },
   "size":2
}

Really hope someone can advise. Starting to pull my hair out on this one.

回答1:

You should use filtered query for facet seach to get exact result:

query do          
  filtered do
     query { <search keywords> }
     filter <your filter> (pass in facet values)
  end
end
<facet>
...
<facet>


回答2:

I was actually very close. As my tags can have multiple I needed to use terms not term ie,

  def self.search(params={})
    tire.search(page: params[:page], per_page: 2, load: true) do
      query do
        boolean do
         must { string params[:name], default_operator: "AND" } if 
         must { term :status, 'live' }
         must { term :refno, params[:refno]} if params[:refno].present?
         must { terms 'tags.name.exact', params[:tag]} if params[:tag].present?
        end
      end
      facet "tags" do
        terms 'tags.name.exact'
      end
      # raise to_json
      # raise to_curl
    end
  end

Thank you for your advise though imotov, Hoang.



回答3:

A search request usually consists of two parts: a query and a filter. If a search request contains only a query part, facets are calculated based on the complete search result. In other words if a search result contains 10 records with the tag "Pet Friendly" and 5 records with the tag "No Pets Allowed", the facet response will contain two facets: "Pet Friendly" and "No Pets Allowed". Now let's assume a user limits results by selecting the "Pet Friendly" tag. If the "Pet Friendly" clause is added to the query part of the request, the search result will be limited to 10 records with the "Pet Friendly" tag, and only one facet will be returned: "Pet Friendly". However, if the "Pet Friendly" clause is added as a filter, the search result will be still limited to 10 records, but two facets will be returned. It happens because facets are calculated based only on the query portion of the search request and query portion didn't change - it still produces search results with 15 records with two different facets.

To answer your question, if a query returns no results (for example, user selected both "Pet Friendly" and "No Pets Allowed" tags) then results have no facets in them, so no facets are returned.