Elasticsearch 2.x, query for tag, and sort results by tag weigth

Eyal Ch

i am using elasticsearch 2.3

i have an index of books. each book has tag, and each tag has weight. i want to get all books that have the requested tag, sorted by tag weight.

for example:

PUT book/book/0
{
    "name": "book 0",
    "tags": [
        {"t": "comedy", "w": 30},
        {"t": "drama","w": 20},
    ]
}

PUT book/book/1
{
    "name": "book 1",
    "tags": [
        {"t": "comedy", "w": 10},
        {"t": "drama","w": 5},
        {"t": "other","w": 50},
    ]
}

PUT book/book/2
    {
        "name": "book 2",
        "tags": [
            {"t": "comedy", "w": 5},
            {"t": "drama","w": 30},
        ]
    }

PUT book/book/3
    {
        "name": "book 3",
        "tags": [
            {"t": "comedy", "w": 5},
            {"t": "other","w": 30},
        ]
    }

i want to search for all books that has tags comedy and drama. the result order is:

  1. book 0 (20+30)
  2. book 2 (30+5)
  3. book 1 (10+5)

UPDATE: i want to return only books that match both tags (and sort only by requested tags). so if i search for 'drama' and 'comedy', only books that has both tags will return (in this case book 0, book 1, book2), sorted by requested tag weights.

how can i get this? any example for query?

Christoph Wurm

Ibrahim's answer is correct if you always want to sum up all weights, even for tags that don't match your query.

If you only want to take the weights of tags into account that you're searching for, you'll have to index tags as a nested object. This is because otherwise all ts and ws are flattened into lists, losing the associations in the process (described here).

Then you can use a function_score query wrapped in a nested query to sum up only the weights of the matching tags. You will have to enable scripting.

Here is an example:

GET /book/_search
{
  "query": {
    "nested": {
      "path": "tags",
      "query": {
        "function_score": {
          "query": {
            "bool": {
              "filter": [
                {
                  "terms": {
                    "tags.t": [
                      "comedy",
                      "drama"
                    ]
                  }
                }
              ]
            }
          },
          "functions": [
            {
              "script_score": {
                "script": "return doc['tags.w'].value"
              }
            }
          ],
          "boost_mode": "replace"
        }
      },
      "score_mode": "sum"
    }
  }
}


=== EDIT following @Eyal Ch's comment ===

If only books matching BOTH tags (comedy and drama in the example) are to be returned, it gets a bit more complicated, as each search term needs its own nested query.

Here's an example:

GET /book/_search
{
  "query": {
    "bool": {
      "must":
      [
        {
          "nested": {
            "path": "tags",
            "query": {
              "function_score": {
                "query": {
                  "term": {
                    "tags.t": {
                      "value": "comedy"
                    }
                  }
                },
                "functions": [
                  {
                    "script_score": {
                      "script": "return doc['tags.w'].value"
                    }
                  }
                ],
                "boost_mode": "replace"
              }
            }
          }
        },
        {
          "nested": {
            "path": "tags",
            "query": {
              "function_score": {
                "query": {
                  "term": {
                    "tags.t": {
                      "value": "drama"
                    }
                  }
                },
                "functions": [
                  {
                    "script_score": {
                      "script": "return doc['tags.w'].value"
                    }
                  }
                ],
                "boost_mode": "replace"
              }
            }
          }
        }
     ]
    }
  }
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related