Reputation: 10056
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:
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?
Upvotes: 1
Views: 145
Reputation: 1072
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 t
s and w
s 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"
}
}
}
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"
}
}
}
}
]
}
}
}
Upvotes: 3
Reputation: 847
Try this:
POST book/book/_search
{
"query": {
"match": {
"tags.t": "comedy drama"
}
},
"sort": [
{
"tags.w": {
"order": "desc",
"mode": "sum"
}
}
]
}
Upvotes: 1