3
votes

I have the following query in Elasticsearch version 1.3.4:

{
   "filtered": {
      "query": {
         "bool": {
            "should": [
               {
                  "bool": {
                     "should": [
                        {
                           "match_phrase": {
                              "_all": "java"
                           }
                        },
                        {
                           "bool": {
                              "should": [
                                 {
                                    "match_phrase": {
                                       "_all": "adobe creative suite"
                                    }
                                 }
                              ]
                           }
                        }
                     ]
                  }
               },
               {
                  "bool": {
                     "should": [
                        {
                           "nested": {
                              "path": "skills",
                              "query": {
                                 "bool": {
                                    "must": [
                                       {
                                          "term": {
                                             "skills.name.original": "java"
                                          }
                                       },
                                       {
                                          "bool": {
                                             "should": [
                                                {
                                                   "match": {
                                                      "skills.source": {
                                                         "query": "linkedin",
                                                         "boost": 5
                                                      }
                                                   }
                                                }, 
                                                {
                                                   "match": {
                                                      "skills.source": {
                                                         "query": "meetup",
                                                         "boost": 5
                                                      }
                                                   }
                                                }                                                
                                             ]
                                          }
                                       }
                                    ],
                                    "minimum_should_match": "100%"
                                 }
                              }
                           }
                        }
                     ]
                  }
               }
            ],
            "minimum_should_match": "100%"
         }
      },
      "filter": {
         "and": [
            {
               "bool": {
                  "should": [
                     {
                        "term": {
                           "skills.name.original": "java"
                        }
                     }
                  ]
               }
            },
            {
               "bool": {
                  "should": [
                     {
                        "term": {
                           "skills.name.original": "ajax"
                        }
                     },
                     {
                        "term": {
                           "skills.name.original": "html"
                        }
                     }
                  ]
               }
            }
         ]
      }
   }
}

Mappings look like this:

  skills: {
    type: "nested", 
    include_in_parent: true, 
    properties: {                 
      name: {
        type: "multi_field",
        fields: {
          name: {type: "string"},
          original: {type : "string", analyzer : "string_lowercase"} 
        }              
      }                                                       
    }
  }

and finally the document structure, for skills (excluded other parts), looks like this:

  "skills": 
  [
    {
      "name": "java",
      "source": [
         "linkedin", 
         "facebook"
      ]
    },
    {
      "name": "html",
      "source": [
         "meetup"
      ]
    }
  ]

My goal with this query is to, first filter out some irrelevant hits with the filters (bottom of the query), then score a person by searching the whole document for the match_phrase "java", extra boosting if it also contains the match_phrase "adobe creative suit", then check the nested value where we get a hit in "skills" to see what kind of "source(s)" the skill came from. Then give the query a boost based on what source, or sources the nested object has.

This kinda of works, at least I don't get any errors, but the final score is odd and its hard to see if its working. If I give a small boost, lets say 2, the score goes DOWN slightly, my top hit at the moment has a score of 32.176407 with boost = 1. With a boost of 5 it goes down to 31.637703. I would expect it to go up, not down? With a boost of 1000, the score goes down to 2.433376.

Is this the right way to do this, or is there a better/easier way? I could change the structure and mappings etc. And why is my score decreasing?

Edit: I have simplified the query a little, only dealing with one "skill":

{
   "filtered": {
      "query": {
         "bool": {
            "must": [
               {
                  "bool": {
                     "must": [
                        {
                           "bool": {
                              "should": [
                                 {
                                    "match_phrase": {
                                       "_all": "java"
                                    }
                                 }
                              ],
                              "minimum_should_match": 1
                           }
                        }
                     ]
                  }
               }
            ],
            "should": [
               {
                  "nested": {
                     "path": "skills",
                     "score_mode": "avg",
                     "query": {
                        "bool": {
                           "must": [
                              {
                                 "term": {
                                    "skills.name.original": "java"
                                 }
                              }
                           ],
                           "should": [
                              {
                                 "match": {
                                    "skills.source": {
                                       "query": "linkedin",
                                       "boost": 1.2
                                    }
                                 }
                              },
                              {
                                 "match": {
                                    "skills.source": {
                                       "query": "meetup",
                                       "boost": 1.2
                                    }
                                 }
                              }
                           ]
                        }
                     }
                  }
               }
            ]
         }
      },
      "filter": {
         "and": [
            {
               "bool": {
                  "should": [
                     {
                        "term": {
                           "skills.name.original": "java"
                        }
                     }
                  ]
               }
            }
         ]
      }
   }
}

The problem now is that I expect two similar documents, where the only difference is the "source" value on the skill "java". They are "linkedin" and "meetup" respectively. In my new query, they both get the same boost, but the final _score is very different for the two documents.

From the query explanation for doc 1:

"value": 3.82485,
"description": "Score based on child doc range from 0 to 125"

and for doc two:

"value": 2.1993546,
"description": "Score based on child doc range from 0 to 125"

These values are the only ones that differ, and I cant see why.

1

1 Answers

0
votes

I can't answer the question regarding the boost, but how many shards do you have on index? TF and IDF are calculated per shard not per index and this could be creating the difference in score. https://groups.google.com/forum/#!topic/elasticsearch/FK-PYb43zcQ.

If you reindex with only 1 shard does change the outcome?

Edit: Also, the doc range is the range of docs for each document in the shard and you can use this to calculate IDF for each doc to verify scores.