5

I am having a problem with multi-match query in RoR. I have Elastic Search configured and working however I am working on setting up aggregations which so far seem to work, but for whatever reason I am not able to search on the field which I am aggregating. This is the extract from my model:

    settings :index => { :number_of_shards => 1 } do
        mapping do
          indexes :id, index: :not_analyzed
          indexes :name
          indexes :summary
          indexes :description

          indexes :occasions, type: 'nested' do
            indexes :id, type: 'integer'
            indexes :occasion_name, type: 'string', index: :not_analyzed

           ... 

          end
        end
      end




  def as_indexed_json(options = {})
    self.as_json(only: [:id, :name, :summary, :description],
                 include: {
                     occasions:           { only: [:id, :occasion_name] },
                     courses:             { only: [:id, :course_name] },
                     allergens:           { only: [:id, :allergen_name] },
                     cookingtechniques:   { only: [:id, :name] },
                     cuisine:             { only: [:id, :cuisine_name]}
                 })
  end


class << self
    def custom_search(query)
      __elasticsearch__.search(query: multi_match_query(query), aggs: aggregations)
    end


    def multi_match_query(query)
      {
          multi_match:
          {
              query: query,
              type: "best_fields",
              fields: ["name^9", "summary^8", "cuisine_name^7", "description^6", "occasion_name^6", "course_name^6", "cookingtechniques.name^5"],
              operator: "and"
          }
      }
    end

I am able to search on all fields as specified in the multi_match_query apart of "occasion_name" which happens to be the field I am aggregating. I have checked that the field is correctly indexed (using elastic search-head plugin). I am also able to display the facets with the aggregated occasion_names in my view. I tried everything I can think of, including removing the aggregation and searching on occasion_name, but still no luck. (I am using the elasticsearch-rails gem)

Any help will be much appreciated.

Edit:

I got this ES query from rails:

@search=
  #<Elasticsearch::Model::Searching::SearchRequest:0x007f91244df460
   @definition=
    {:index=>"recipes",
     :type=>"recipe",
     :body=>
      {:query=>
        {:multi_match=>
          {:query=>"Christmas",
           :type=>"best_fields",
           :fields=>["name^9", "summary^8", "cuisine_name^7", "description^6", "occasion_name^6", "course_name^6", "cookingtechniques.name^5"],
           :operator=>"and"}},
       :aggs=>
        {:occasion_aggregation=>
          {:nested=>{:path=>"occasions"}, :aggs=>{:id_and_name=>{:terms=>{:script=>"doc['occasions.id'].value + '|' + doc['occasions.occasion_name'].join(' ')", :size=>35}}}}}}},

This is an example of all that gets indexed for 1 of my dummy recipes I use for testing (the contents are meaningless - I use this only for testing):

{
"_index": "recipes",
"_type": "recipe",
"_id": "7",
"_version": 1,
"_score": 1,
"_source": {
"id": 7,
"name": "Mustard-stuffed chicken",
"summary": "This is so good we'd be surprised if this chicken fillet recipe doesn't become a firm favourite. Save it to your My Good Food collection and enjoy",
"description": "Heat oven to 200C/fan 180C/gas 6. Mix the cheeses and mustard together. Cut a slit into the side of each chicken breast, then stuff with the mustard mixture. Wrap each stuffed chicken breast with 2 bacon rashers – not too tightly, but enough to hold the chicken together. Season, place on a baking sheet and roast for 20-25 mins.",
"occasions": [
{
"id": 9,
"occasion_name": "Christmas"
}
,
{
"id": 7,
"occasion_name": "Halloween"
}
,
{
"id": 8,
"occasion_name": "Bonfire Night"
}
,
{
"id": 10,
"occasion_name": "New Year"
}
],
"courses": [
{
"id": 9,
"course_name": "Side Dish"
}
,
{
"id": 7,
"course_name": "Poultry"
}
,
{
"id": 8,
"course_name": "Salad"
}
,
{
"id": 10,
"course_name": "Soup"
}
],
"allergens": [
{
"id": 6,
"allergen_name": "Soya"
}
,
{
"id": 7,
"allergen_name": "Nut"
}
,
{
"id": 8,
"allergen_name": "Other"
}
,
{
"id": 1,
"allergen_name": "Dairy"
}
],
"cookingtechniques": [
{
"id": 15,
"name": "Browning"
}
],
"cuisine": {
"id": 1,
"cuisine_name": "African"
}
}
}

EDIT 2:

I managed to make the search work for occasions as suggested by @rahulroc, but now I can't search on anything else...

    def multi_match_query(query)
  {
      nested:{
           path: 'occasions',
          query:{
      multi_match:
      {
          query: query,
          type: "best_fields",
          fields: ["name^9", "summary^8", "cuisine_name^7", "description^6", "occasion_name^6", "course_name^6", "cookingtechniques.name^5"],
          operator: "and"
      }
    }

      }
  }
end

UPDATE: Adding multiple nested fields - I am trying to add the rest of my aggregations but I am facing similar problem as before. My end goal will be to use the aggregations as filters so I need to add about 4 more nested fields to my query (I also would like to have the fields searchable) Here is the working query as provided by @rahulroc + the addition of another nested field which I can't search on. As before in terms of indexing everything is working and I can display the aggregations for the newly added field, but I can't search on it. I tried different variations of this query but I couldn't make it work (the rest of the fields are still working and searchable - the problem is just the new field):

 def multi_match_query(query)
      {

        bool: {
            should: [
                {
                    nested:{
                        path: 'occasions',
                        query: {
                            multi_match:
                            {
                                      query: query,
                                      type: "best_fields",
                                      fields: ["occasion_name"]

                                  }
                        }
                    }
                },

                {
                    nested:{
                        path: 'courses',
                        query: {
                            multi_match:
                                {
                                    query: query,
                                    type: "best_fields",
                                    fields: ["course_name"]

                                }
                        }
                    }
                },

                {
                    multi_match: {
                        query: query,
                        fields:["name^9", "summary^8", "cuisine_name^7", "description^6"],

                    }
                }
            ]
        }


      }
    end
3
  • I'm not familiar with rails but have some ES experience. Are you able to show the JSON query that gets sent to ElasticSearch? Commented Mar 28, 2016 at 23:44
  • Hi, I just edit my first post - I have included the query. Thanks Commented Mar 29, 2016 at 0:46
  • occasion_name is a nested field. It can not be directly accessed in match query Commented Mar 29, 2016 at 2:16

1 Answer 1

8

You need to create a separate nested clause for matching a nested field

"query": {
    "bool": {
        "should": [
            {
                "nested": {
                    "path": "occassions",
                    "query": {
                        "multi_match": {
                            "query": "Christmas",
                            "fields": ["occassion_name^2"]
                        }
                    }
                } 
            },
            {
                "multi_match": {
                    "query": "Christmas",
                    "fields":["name^9", "summary^8", "cuisine_name^7", "description^6","course_name^6"]                }
            }
        ]
    }
}
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the suggestion, I managed to make the search work for occasions as per edit 2, but now I can't search anything else
The other fields do not belong to the nested scope of occassions. Other fields need to be in their respective scope. Make separate clauses in bool-should clause. I will provide the full query in some time.
I am risking to get annoying, but I need help again... I tried to add my other aggregations following the method described by @rahulroc - adding another { nested:{path: 'courses',query: {multi_match: {query: query,type: "best_fields", fields: ["course_name"]}}}} inside the "should" clause, but the newly added nested field is not searchable. I checked the ElasticSearch Definitive Guide, but there is example only with one nested field. In another question on StackOverflow, someone has provided a query exactly the way I am doing it with multiple nested fields but mine doesn't work...
I have just updated it with the new query. Thank you for your help!
Wouldn't the nested field need to be occassions.occassion_name^2? (i.e. with occassions. prefix)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.