【问题标题】:Elasticsearch: Influence scoring with custom score field in document pt.2Elasticsearch:在文档 pt.2 中使用自定义评分字段进行影响评分
【发布时间】:2017-08-02 11:59:58
【问题描述】:

拥有这些文件:

{
  "created_at" : "2017-07-31T20:30:14-04:00",
  "description" : null,
  "height" : 3213,
  "id" : "1",
  "tags" : [
    {
      "confidence" : 65.48948436785749,
      "tag" : "beach"
    },
    {
      "confidence" : 57.31950504425406,
      "tag" : "sea"
    },
    {
      "confidence" : 43.58207236617374,
      "tag" : "coast"
    },
    {
      "confidence" : 35.6857910950816,
      "tag" : "sand"
    },
    {
      "confidence" : 33.660057321079655,
      "tag" : "landscape"
    },
    {
      "confidence" : 32.53252312423727,
      "tag" : "sky"
    }
  ],
  "width" : 5712,
  "color" : "#0C0A07",
  "boost_multiplier" : 1
}

{
  "created_at" : "2017-07-31T20:43:17-04:00",
  "description" : null,
  "height" : 4934,
  "id" : "2",
  "tags" : [
    {
      "confidence" : 84.09123410403951,
      "tag" : "mountain"
    },
    {
      "confidence" : 56.412795342449456,
      "tag" : "valley"
    },
    {
      "confidence" : 48.36547551196872,
      "tag" : "landscape"
    },
    {
      "confidence" : 40.51100450186575,
      "tag" : "mountains"
    },
    {
      "confidence" : 33.14263528292239,
      "tag" : "sky"
    },
    {
      "confidence" : 31.064394646169404,
      "tag" : "peak"
    },
    {
      "confidence" : 29.372,
      "tag" : "natural elevation"
    }
  ],
  "width" : 4016,
  "color" : "#FEEBF9",
  "boost_multiplier" : 1
}

我想根据每个标签的置信度值计算 _score。例如,如果您搜索“mountain”,它应该只返回 id 为 1 的文档,如果您搜索“landscape”,则 2 的分数应该高于 1,因为 2 中的景观置信度高于 1(48.36 对 33.66)。如果你搜索“coast Landscape”,这个时间分数 1 应该高于 2,因为 doc 1 在 tags 数组中同时有 Coast 和 Landscape。我还想将分数与“boost_multiplier”相乘,以提升某些文档与其他文档的对比。

我在 SO 中发现了这个问题,Elasticsearch: Influence scoring with custom score field in document

但是当我尝试接受的解决方案时(我在我的 ES 服务器中启用了脚本),无论搜索词是什么,它都会返回 _score 1.0 的两个文档。这是我尝试过的查询:

{
  "query": {
    "nested": {
      "path": "tags",
      "score_mode": "sum",
      "query": {
        "function_score": {
          "query": {
            "match": {
              "tags.tag": "coast landscape"
            }
          },
          "script_score": {
            "script": "doc[\"confidence\"].value"
          }
        }
      }
    }
  }
}

我还尝试了 @yahermann 在 cmets 中的建议,将“script_score”替换为“field_value_factor”:{“field”:“confidence”},结果仍然相同。知道为什么会失败,或者有更好的方法吗?

为了获得完整的图片,这是我使用的映射定义:

{
  "mappings": {
    "photo": {
      "properties": {
        "created_at": {
          "type": "date"
        },
        "description": {
          "type": "text"
        },
        "height": {
          "type": "short"
        },
        "id": {
          "type": "keyword"
        },
        "tags": {
          "type": "nested",
          "properties": {
            "tag": { "type": "string" },
            "confidence": { "type": "float"}
          }
        },
        "width": {
          "type": "short"
        },
        "color": {
          "type": "string"
        },
        "boost_multiplier": {
          "type": "float"
        }
      }
    }
  },
  "settings": {
    "number_of_shards": 1
  }
}

更新 按照下面@Joanna 的回答,我尝试了查询,但实际上,无论我在匹配查询、coast、foo、bar 中输入什么,它总是返回两个文档的 _score 1.0,我在 elasticsearch 2.4 上尝试过。 Docker 中的 6、5.3、5.5.1。这是我得到的回复:

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Content-Length: 1635

{"took":24,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":2,"max_score":1.0,"hits":[{"_index":"my_index","_type":"my_type","_id":"2","_score":1.0,"_source":{
  "created_at" : "2017-07-31T20:43:17-04:00",
  "description" : null,
  "height" : 4934,
  "id" : "2",
  "tags" : [
    {
      "confidence" : 84.09123410403951,
      "tag" : "mountain"
    },
    {
      "confidence" : 56.412795342449456,
      "tag" : "valley"
    },
    {
      "confidence" : 48.36547551196872,
      "tag" : "landscape"
    },
    {
      "confidence" : 40.51100450186575,
      "tag" : "mountains"
    },
    {
      "confidence" : 33.14263528292239,
      "tag" : "sky"
    },
    {
      "confidence" : 31.064394646169404,
      "tag" : "peak"
    },
    {
      "confidence" : 29.372,
      "tag" : "natural elevation"
    }
  ],
  "width" : 4016,
  "color" : "#FEEBF9",
  "boost_multiplier" : 1
}
},{"_index":"my_index","_type":"my_type","_id":"1","_score":1.0,"_source":{
  "created_at" : "2017-07-31T20:30:14-04:00",
  "description" : null,
  "height" : 3213,
  "id" : "1",
  "tags" : [
    {
      "confidence" : 65.48948436785749,
      "tag" : "beach"
    },
    {
      "confidence" : 57.31950504425406,
      "tag" : "sea"
    },
    {
      "confidence" : 43.58207236617374,
      "tag" : "coast"
    },
    {
      "confidence" : 35.6857910950816,
      "tag" : "sand"
    },
    {
      "confidence" : 33.660057321079655,
      "tag" : "landscape"
    },
    {
      "confidence" : 32.53252312423727,
      "tag" : "sky"
    }
  ],
  "width" : 5712,
  "color" : "#0C0A07",
  "boost_multiplier" : 1
}
}]}}

UPDATE-2 我在 SO 上找到了这个:Elasticsearch: "function_score" with "boost_mode":"replace" ignores function score

它基本上说,如果函数不匹配,则返回 1。这是有道理的,但我正在为相同的文档运行查询。这令人困惑。

最终更新 终于发现问题了,傻了。 ES101,如果您向搜索 api 发送 GET 请求,它会返回所有分数为 1.0 的文档 :) 您应该发送 POST 请求...谢谢@Joanna,它完美运行!!!

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    你可以试试这个查询 - 它结合了两个评分:confidenceboost_multiplier 字段:

    {
      "query": {
        "function_score": {
            "query": {
                "bool": {
                    "should": [{
                        "nested": {
                          "path": "tags",
                          "score_mode": "sum",
                          "query": {
                            "function_score": {
                              "query": {
                                "match": {
                                  "tags.tag": "landscape"
                                }
                              },
                              "field_value_factor": {
                                "field": "tags.confidence",
                                "factor": 1,
                                "missing": 0
                              }
                            }
                          }
                        }
                    }]
                }
            },
            "field_value_factor": {
                "field": "boost_multiplier",
                "factor": 1,
                "missing": 0
            }
          }
        }
    } 
    

    当我使用 coast 术语搜索时 - 它返回:

    • 带有id=1的文档,因为只有这个有这个词,评分是"_score": 100.27469

    当我使用 landscape 术语搜索时 - 它会返回两个文档:

    • 带有id=2 且得分为“_score”的文档:85.83046
    • 带有id=1 且得分为“_score”的文档:59.7339

    id=2 的文档具有较高的 confidence 字段值,因此得分较高。

    当我使用 coast landscape 术语搜索时 - 它返回两个文档:

    • 带有id=1 且得分为“_score”的文档:160.00859
    • 带有id=2 且评分为“_score”的文档:85.83046

    虽然id=2 的文档具有更高的confidence 字段值,但id=1 的文档具有两个匹配词,因此得分更高。通过更改"factor": 1 参数的值,您可以决定confidence 对结果的影响程度。

    boost_muliplier 字段

    当我索引一个新文档时会发生更有趣的事情:假设它与带有id=2 的文档几乎相同,但我设置了"boost_multiplier" : 4"id": 3

    {
      "created_at" : "2017-07-31T20:43:17-04:00",
      "description" : null,
      "height" : 4934,
      "id" : "3",
      "tags" : [
        ...
        {
          "confidence" : 48.36547551196872,
          "tag" : "landscape"
        },
        ...
      ],
      "width" : 4016,
      "color" : "#FEEBF9",
      "boost_multiplier" : 4
    }
    

    使用coast landscape term 运行相同的查询会返回三个文档:

    • 带有id=3 且得分为“_score”的文档:360.02664
    • 带有id=1 且评分为“_score”的文档:182.09859
    • 带有id=2 且得分为“_score”的文档:90.00666

    虽然带有id=3 的文档只有一个匹配词(landscape),但它的boost_multiplier 值大大提高了得分。在这里,使用"factor": 1,您还可以决定这个值应该增加多少得分,并使用"missing": 0 决定如果没有这样的字段被索引应该发生什么。

    【讨论】:

    • 感谢详细解答!当我尝试使用海岸查询时,我仍然得到两个文档,并且它们的分数相等,1.0。事实上,无论我尝试作为搜索词,它总是返回所有文档,并且它们的分数都是 1.0。我相信ES中的设置有问题?我使用的是 5.3 版。
    • 我已经更新了问题,添加了运行查询后得到的响应。
    • 现在一切正常,我使用的是 get 请求而不是 post :) 再次感谢详细回答!
    猜你喜欢
    • 1970-01-01
    • 2018-01-10
    • 1970-01-01
    • 2015-03-21
    • 2017-03-04
    • 1970-01-01
    • 2013-08-23
    • 1970-01-01
    • 2012-10-17
    相关资源
    最近更新 更多