2016-08-15 6 views
1

Я пользуюсь elasticsearch 2.3Elasticsearch 2.x, запрос для тега и сортировка результатов по тегу weigth

У меня есть индекс книг. каждая книга имеет тег, и каждый тег имеет вес. Я хочу получить все книги с запрошенным тегом, отсортированные по весу тегов.

, например:

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}, 
     ] 
    } 

я хочу, чтобы найти все книги, которые имеет теги комедии и драмы. порядок результат:

  1. книга 0 (20 + 30)
  2. Книга 2 (30 + 5)
  3. Книга 1 (10 + 5)

ОБНОВЛЕНИЕ: я хочу чтобы возвращать только книги, соответствующие обоим тегам (и сортировать только по запрошенным тегам). поэтому, если я ищу «драму» и «комедию», возвращаются только те книги, у которых есть оба тега (в данном случае книга 0, книга 1, книга2), отсортированные по требуемым весам тегов.

как я могу это получить? любой пример запроса?

ответ

3

Ibrahim's answer является правильным, если вы всегда хотите, чтобы суммировать все веса, даже для тегов, которые не соответствуют Вашему запросу.

Если вы хотите только учитывать веса тегов, которые вы ищете, вам нужно будет проиндексировать tags как объект nested. Это связано с тем, что в противном случае все t s и w s сплющиваются в списки, теряя ассоциации в процессе (описано here).

Затем вы можете использовать запрос function_score, завернутый в запрос nested, чтобы суммировать только весы совпадающих тегов. Вам нужно будет включить scripting.

Вот пример:

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" 
    } 
    } 
} 


=== РЕДАКТИРОВАТЬ следующий комментарий @Eyal Ch в ===

Если только книги, соответствующие ОБА теги (комедии и драмы в примере) должны быть возвращены, это становится немного сложнее, так как каждому поисковому запросу нужен свой собственный запрос nested.

Вот пример:

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" 
       } 
      } 
      } 
     } 
    ] 
    } 
    } 
} 
+0

thanks @Christoph Wurm. единственная проблема, с которой я сталкиваюсь сейчас, заключается в том, что она вернет все книги, комедии или драмы, в тегах. но мне нужны все книги, комедии и драмы в тегах. вы можете помочь? –

+0

@EyalCh Да, я положил его в ответ. –

+0

спасибо, что работает !. просто чтобы понять: в вашем обновленном ответе я не вижу «score_mode»: «sum». как это окупить счет? это по умолчанию?если я хочу забить его другим счетом (например, avg?). Благодарю. –

1

Попробуйте это:

POST book/book/_search 
{ 
    "query": { 
     "match": { 
      "tags.t": "comedy drama" 
     } 
    }, 
    "sort": [ 
     { 
      "tags.w": { 
      "order": "desc", 
      "mode": "sum" 
      } 
     } 
    ] 
} 
+0

это будет сортировать «ш» из всех тегов. Я хочу отсортировать его только по порядку запрошенных тегов (w of comedy + w of drama) –