Elasticsearch按喜欢和不喜欢排序

时间:2018-06-19 00:16:35

标签: elasticsearch elasticsearch-5

我一直在努力表达我正试图用Elasticsearch解决的当前逻辑问题,我认为我有一个很好的方式来代表它。

假设我正在构建一个API,以便根据用户的喜好对Mario Kart字符进行排序。用户可以列出他们喜欢的字符以及他们不喜欢的字符。这是数据集:

{character: {name: "Mario", weight: "Light"}},
{character: {name: "Luigi", weight: "Medium"}},
{character: {name: "Peach", weight: "Light"}},
{character: {name: "Bowser", weight: "Heavy"}},
{character: {name: "Toad", weight: "Light"}},
{character: {name: "Koopa", weight: "Medium"}}

用户输入他们喜欢的MarioLuigi,并且不喜欢Bowser。使用Elasticsearch,我怎样才能为用户排序这些数据,因此返回列表如下:

[Mario (+), Luigi (+), Peach, Toad, Koopa, Bowser (-)]

*在那里有优缺点。

这将返回用户在前面的最佳选择,中间可以选择的那些,以及最后他们不喜欢的那些。必须使用嵌套查询才能让我在这里绊倒。

发展查询,假设有一个团队模式,每个团队由两对组成,由游戏决定:

[Luigi (+), Bowser (-)]
[Mario (+), Peach]
[Toad, Koopa]

如何确保我不会过滤掉包含Bowser的小组,但仍会对结果进行加权,以便它如此:

[Mario (+), Peach]
[Toad, Koopa]
[Luigi (+), Bowser (-)]

或者,[Luigi, Bowser]实际排名第二?

我对在Elasticsearch中构建类似这些复杂查询感到非常困惑,并且非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

根据您的映射,类似

GET /characters/_search
        {
   "sort":[
      "_score"
   ],
   "query":{
      "bool":{
         "should":[
            {
               "constant_score":{
                  "filter":{
                     "term":{
                        "name.keyword":"Mario"
                     }
                  },
                  "boost":2.0
               }
            },
            {
               "constant_score":{
                  "filter":{
                     "term":{
                        "name.keyword":"Luigi"
                     }
                  },
                  "boost":2.0
               }
            },
            {
               "constant_score":{
                  "filter":{
                     "term":{
                        "name.keyword":"Peach"
                     }
                  },
                  "boost":1.0
               }
            },
            {
               "constant_score":{
                  "filter":{
                     "term":{
                        "name.keyword":"Toad"
                     }
                  },
                  "boost":1.0
               }
            },
            {
               "constant_score":{
                  "filter":{
                     "term":{
                        "name.keyword":"Koopa"
                     }
                  },
                  "boost":1.0
               }
            },
            {
               "constant_score":{
                  "filter":{
                     "term":{
                        "name.keyword":"Bowser"
                     }
                  },
                  "boost":0
               }
            }
         ]
      }
   }
}

应该工作。 PS:如果您有一个嵌套映射,然后用一个嵌套查询子句将布尔查询包围起来并调整字段名路径。要仅返回名称字段,请在查询之前添加_source子句,并将名称路径作为值。

答案 1 :(得分:0)

首先我要说-IMHO为此使用Elasticsearch是主要的矫kill过正。您可能应该使用更简单的内存数据结构来进行此计算。

假设您决定通过Elasticsearch实施此操作,那么我将做以下事情:

1)使用此映射将每个字符表示为文档-

PUT game/characters/_mapping
{
  "properties": {
    "name":{
      "type": "keyword"
    },
    "weight": {
      "type": "keyword"
    }
  }
}

2)每个字符将如下所示:

PUT game/characters/boswer
{
  "name": "bowser",
  "weight": "heavy"
}

3)然后,您可以像@ sramalingam24所建议的那样按喜欢的顺序获取它们。请注意,增强必须为非负数,因此您需要将字符的相似度“标准化”到大于零的范围:

GET game/characters/_search
{
  "size": 100,
  "query": {
    "bool": {
      "should": [
        {
          "constant_score": {
            "filter": {
              "term": {
                "name": "Peach"
              }
            },
            "boost": 2
          }
        },{
          "constant_score": {
            "filter": {
              "term": {
                "name": "Mario"
              }
            },
            "boost": 2
          }
        },{
          "constant_score": {
            "filter": {
              "term": {
                "name": "Toad"
              }
            },
            "boost": 1
          }
        },{
          "constant_score": {
            "filter": {
              "term": {
                "name": "Bowser"
              }
            },
            "boost": 0
          }
        },
      ]
    }
  }
}

祝你好运!