rubyprince
rubyprince

Reputation: 17793

Adding sort priority to documents matching certain condition

I am looking for a way to do this. I need to show all experts inside the users mapping. (Experts are documents with field role equals 3). But while showing the experts, I need to show experts having "Linkedin" inside their social medias (social_medias is an array field in the users mapping) first and those without "Army" afterwards. For ex:, I have 5 documents:

[
  {
    role: 3,
    name: "David",
    social_medias: ["Twitter", "Facebook"]
  },
  {
    role: 3,
    name: "James",
    social_medias: ["Facebook", "Linkedin"]
  },
  {
    role: 3,
    name: "Michael",
    social_medias: ["Linkedin", "Facebook"]
  },
  {
    role: 3,
    name: "Peter",
    social_medias: ["Facebook"]
  },
  {
    role: 3,
    name: "John",
    social_medias: ["Facebook", "Twitter"]
  },
  {
    role: 2,
    name: "Babu",
    social_medias: ["Linkedin", "Facebook"]
  }
]

So, I want to get documents with role 3 and while fetching it, documents having "Linkedin" in social media should come first. So, the output after query should be in this order:

[
  {
    role: 3,
    name: "James",
    social_medias: ["Facebook", "Linkedin"]
  },
  {
    role: 3,
    name: "Michael",
    social_medias: ["Linkedin", "Facebook"]
  },
  {
    role: 3,
    name: "David",
    social_medias: ["Twitter", "Facebook"]
  },
  {
    role: 3,
    name: "Peter",
    social_medias: ["Facebook"]
  },
  {
    role: 3,
    name: "John",
    social_medias: ["Facebook", "Twitter"]
  }
]

I am trying with function_score now. I can specify a column to have more priority in function_score, but cant figure out how to specify condition based priority.

Upvotes: 0

Views: 642

Answers (1)

Andrei Stefan
Andrei Stefan

Reputation: 52368

Why not let the default sorting in ES (sort by score) do the job for you, without custom ordering or custom scoring:

GET /my_index/media/_search
{
  "query": {
    "filtered": {
      "query": {
        "bool": {
          "should": [
            {"match": {"social_medias": "Linkedin"}},
            {"match_all": {}},
            {"query_string": {
               "default_field": "social_medias",
               "query": "NOT Army"
            }}
          ]
        }
      },
      "filter": {
        "term": {
          "role": "3"
        }
      }
    }
  }
}

The query above filters for "role":"3" and then in a should clause it basically says: if the documents match social_medias field with value Linkedin then give them a score based on this matching. To, also, include all others documents that don't match Linkedin, add another should for match_all. Now, everything that matches match_all gets a score. If those documents, also, match Linkedin then they get an additional score, thus making them score higher and be first in the list of results.

Upvotes: 3

Related Questions