首页 > 其他分享 >Elasticsearch 自定义评分

Elasticsearch 自定义评分

时间:2024-05-10 18:00:12浏览次数:22  
标签:index 自定义 评分 defScore score Elasticsearch 文档

一.概述

  在前几章中,讲到了如何分词,以及分词的种类。 分词后在进行全文检索时,返回结果如何确定用户真正想看到的,  那数据结果如何排序呢?

  比如在电商中:搜索一个商品关键词,默认是综合排序,商品如何顺序是经过一定的算法策略,也是为了提高用户的体验。Elasticsearch使用评分算法,对搜索结果进行排序,评分越高的文档,相关度就越高,排序就越在最前面。

  下面探讨自定义评分策略的应用场景、搜索结果的相关度以及如何进行自定义评分,以便在搜索时获得最符合用户需求的结果。

  Elasticsearch自定义评分的主要作用如下:

    1)排序偏好:通过在搜索结果中给每个文档自定义评分,可以更好地满足搜索用户的排序偏好。

    2)特殊字段权重:通过给特定字段赋予更高的权重,可以让这些字段对搜索结果的影响更大。
    3)业务逻辑需求:根据业务需求,可以定义复杂的评分逻辑,使搜索结果更符合业务需求。
    4)自定义用户行为:可以使用用户行为数据(如点击率)作为评分因素,提高用户搜索体验。

  搜索引擎本质是一个匹配过程,即从海量的数据中找到匹配用户需求的内容。判定内容与用户查询的相关度一直是搜索引擎领域的核心研究课题之一。如果搜索引擎不能准确地识别用户查询的意图并将相关结果排在前面的位置,那么搜索结果就不能满足用户的需求,从而影响用户对搜索引擎的满意度。

  通过如match的全文检索,搜索出来的结果,每个文档有一个分数,分数字段为_score, 文档如下所示:

 "hits" : {
    "total" : {
      "value" : 777935,
      "relation" : "eq"
    },
    "max_score" : 2.70161664E8,
    "hits" : [
      {
        "_index" : "hqbuy_stock",
        "_type" : "_doc",
        "_id" : "541753335779440",
        "_score" : 2.70161664E8,
        "_source" : {
          "Id" : "541753335779440",
          "StockGuid" : "3a123e8a-690c-ec77-9503-0e2004fa47d4",
          "PartNo" : "VTTEST11",
          "Brand" : "VELLEMAN",

  

二.评分概述

  Lucene(或Elasticsearch)使用布尔模型查找匹配文档,并用一个名为“实用评分函数”的公式来计算相关度。从Elasticsearch 5之后,默认的打分机制改成了Okapi BM25。其中BM是Best Match的缩写,25是指经过25次迭代调整之后得出的算法,它是由TF-IDF机制进化来的。BM25都使用逆向文档频率来区分普通词(不重要)和非普通词(重要),使用词频来衡量某个词在文档中出现的频率。文档里的某个词出现得越频繁,文档与这个词就越相关,得分越高。

  2.1影响相关度评分的查询子句

    在布尔查询中,每个must、should和must_not元素都称为查询子句。

    根据文档满足must或should标准的程度,可以确定文档的相关度评分。分数越高,文档就越符合的搜索条件。

    must_not子句中的条件被视为“过滤器"。它会决定文档是否包含在结果中,但不会影响文档的评分方式。

    filter 是必须匹配条件,决定包含或排除文档。不会影响文档的评分方式。

  总结就是:must和should中的子查询会影响评分,而must_not和filter中的子查询不会影响评分。

    下面示例在布尔查询中,filter来过滤不影响评分:

POST /hqbuy_stock/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "PartNo": {
            "value": "TEST"
          }
        }
      }
    }
  }
}

     查询文档结果中_score字估为0,如下所示:

 "hits" : [
      {
        "_index" : "hqbuy_stock",
        "_type" : "_doc",
        "_id" : "541592065478725",
        "_score" : 0.0,
        "_source" : {
          "Id" : "541592065478725",
          "StockGuid" : "3a123bc5-b1e3-718f-3bde-3420aae666b5",
          "PartNo" : "TEST",
          "Brand" : "TEXAS INSTRUMENTS/德州仪器",
          "Encapsulation" : "",
          "DateCode" : "2024+",
          "DateCodes" : [
            {
              "Qty" : 1000,
              "DateCodeNo" : "2024+"
            }
          ],

 

三.自定义评分示例  

  自定义评分的核心是通过修改评分来修改文档相关度,在最前面的位置返回用户最期望的结果。然而,如何实现这样的自定义评分策略,以确保搜索结果能够最大限度地满足用户需求呢?我们可以从多个层面,包括索引层面、查询层面以及后处理阶段着手。

  3.1 Index Boost:在索引层面修改相关度

    Index Boost这种方式能在跨多个索引搜索时为每个索引配置不同的级别。所以它适用于索引级别调整评分。

    例如:一批数据里有不同的标签,数据结构一致,要将不同的标签存储到不同的索引(A、B、C),并严格按照标签来分类展示(先展示A类,然后展示B类,最后展示C类),应该用什么方式查询呢?

    借助indices_boost提升索引的权重,让A排在最前,其次是B,最后是C。

PUT my_index_a/_doc/1
{
   "subject": "subject 1"
}

PUT my_index_b/_doc/2
{
   "subject": "subject 2"
}

PUT my_index_c/_doc/3
{
   "subject": "subject 3"
}

    检查索引,在索引级别中设置索引boost的相关度值,这里my_index_a的相关度值为最高,搜索的结果得分也会最高。

get  my_index_*/_search
{
  "indices_boost":[
    {
      "my_index_a":15
    },{
      "my_index_b":5
    },{
      "my_index_c":3
    }
    ],
    "query":{
      "match_phrase_prefix": {
        "subject": {
          "query": "subject"
        }
      }
    }
}

    搜索文档结果得分如下所示:

 "hits" : [
      {
        "_index" : "my_index_a",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 2.002971,
        "_source" : {
          "subject" : "subject 1"
        }
      },
      {
        "_index" : "my_index_b",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.66765696,
        "_source" : {
          "subject" : "subject 2"
        }
      },
      {
        "_index" : "my_index_c",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.5469647,
        "_source" : {
          "subject" : "subject 3"
        }
      }
    ]

     

  3.2 boosting:修改文档相关度

    boosting可在查询时修改文档的相关度。boosting值所在范围不同,含义也不同。若boosting值为0~1,如0.2,代表降低评分;若boosting值>1,如1.5,则代表提升评分。适用于某些特定的查询场景,用户可以自定义修改满足某个查询条件的结果评分。

POST /hqbuy_stock/_search
{
  "query": {
    "match_phrase": {
      "PartNo.Like": {
        "query": "TEST2",
        "boost":10
      }
    }
  }
}

 

  3.3 function_score:自定义评分   

    下面介绍终级杀招 function_score的使用。对于negative_boost---降低相关度,这里不在介绍,用function_score来替代实现更加灵活。

    function_score方式支持用户自定义一个或多个查询语句及脚本,达到精细化控制评分的目的,以对搜索结果进行高度个性化的排序设置。适用于需进行复杂查询的自定义评分业务场景。

    先看一个简单示例,根据销量和浏览人数进行相关度提升。评分公式: 评分=原始评分*(销量+销售人数)

      创建索引并批量加入数据,如下所示:

put my_index_1006/_bulk
  {"index":{"_id":1}}
  {"name":"A","sales":10,"visitors":10}
  {"index":{"_id":2}}
  {"name":"B","sales":20,"visitors":20}
  {"index":{"_id":3}}
  {"name":"C","sales":30,"visitors":30}

      检索数据,使用function_score设置自定义评分规则

post my_index_1006/_search
{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "script_score": {
        "script": "_score * (doc['sales'].value+doc['visitors'].value)"
      }
    }
  }
}

     查看文档的评分如下所示:

  "hits" : [
      {
        "_index" : "my_index_1006",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 60.0,
        "_source" : {
          "name" : "C",
          "sales" : 30,
          "visitors" : 30
        }
      },
      {
        "_index" : "my_index_1006",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 40.0,
        "_source" : {
          "name" : "B",
          "sales" : 20,
          "visitors" : 20
        }
      },
      {
        "_index" : "my_index_1006",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 20.0,
        "_source" : {
          "name" : "A",
          "sales" : 10,
          "visitors" : 10
        }
      }
    ]

 

四.自定义评分实战

    搜索背景:元器件商城关键词搜索,自定义评分规则如下:

    1)关键词完全匹配型号,显示优先级最高。

    2)关键词完全匹配品牌,显示优先级最高。

    3)关键词前缀匹配型号,显示优先级往后。

    4)关键词前缀匹配品牌,显示优先级往后。

    6)关键词模糊匹配型号,显示优先级再往后。  

    6)关键词模糊匹配品牌,显示优先级再往后。

    7)关键词模糊匹配描述、分类,显示优先级再往后。

    8)过期的物料--显示往后排。

    9)自营的比非自营优先显示。

    10) 有库存的比没有库存的优先显示。

    自定义的评分搜索脚本如下所示:

POST /stock/_search
{
  "track_total_hits": true,
  "from": 0,
  "highlight": {
    "fields": {
      "PartNo.Like": {},
      "Brand.Like": {},
      "SearchKeyword.Like": {}
    }
  },
  "query": {
    "function_score": {
      "functions": [
        {
          "script_score": {
            "script": {
              "source": "def defScore=1; def _expirationDateStamp = doc['ExpirationDateStamp'].value; 
                if (params.currTime > _expirationDateStamp ) { defScore = defScore+0.1; }else { defScore = defScore+0.2; }
                return defScore * _score;", "params": { "currTime": 1715334246 } } } }, { "script_score": { "script": { "source": "def defScore=1; def _stockType = doc['StockType'].value;if (_stockType == 1 ) { defScore = defScore+0.5; }
else { defScore = defScore+0.1; } return defScore * _score;" } } }, { "script_score": { "script": { "source": "def defScore=1; def _stockQty = doc['StockQty'].value;if (_stockQty > 0 ) { defScore = defScore+0.3; }
               else { defScore = defScore+0.1; } return defScore * _score;" } } } ], "query": { "bool": { "filter": [ { "term": { "StockStatus": { "value": 1 } } } ], "minimum_should_match": 1, "should": [ { "term": { "PartNo": { "value": "TEST", "boost": 1000 } } }, { "term": { "Brand": { "value": "TEST", "boost": 1000 } } }, { "match_phrase_prefix": { "PartNo.Like": { "query": "TEST", "boost": 2 } } }, { "match": { "PartNo.Like": { "query": "TEST", "boost": 2 } } }, { "match_phrase_prefix": { "Brand.Like": { "query": "TEST", "boost": 2 } } }, { "match": { "Brand.Like": { "query": "TEST", "boost": 2 } } }, { "match": { "SearchKeyword.Like": { "query": "TEST", "boost": 0.6 } } } ] } }, "score_mode": "sum" } }, "size": 20, "sort": [ { "_score": { "order": "desc" } } ], "_source": { "excludes": [ "BatchNumber", "UniqueId", "SearchKeyword" ] } }

 

参考文献资料:一本书讲透Elasticsearch

    

 

标签:index,自定义,评分,defScore,score,Elasticsearch,文档
From: https://www.cnblogs.com/MrHSR/p/18152472

相关文章

  • NET6 自定义授权中间件
    AuthorizationWithCustMiddleware///<summary>///自定义授权中间件类:使用身份验证中间件存储的身份信息来进行权限验证///一定要先启用身份验证中间件(app.UseAuthentication()),它会验证请求中的身份信息,并将身份信息存储在HttpContext.User属性中///如果没有启用身份......
  • elasticsearch 数据远程备份与还原
    官方文档:备份集群:https://www.elastic.co/guide/cn/elasticsearch/guide/current/backing-up-your-cluster.html#backing-up-your-cluster恢复数据:https://www.elastic.co/guide/cn/elasticsearch/guide/2.x/_restoring_from_a_snapshot.htmles官方默认是备份数据到本地的,如果......
  • 自定义鼠标设置-中键设置为后退
    这个软件能够修改鼠标的很多设置公司配置的鼠标没有侧边按键导致没有后退按键可以使用,使阅读代码不够流畅使用这款软件就能将中间设置为后退,使阅读代码更加流畅下载网站为https://www.highrez.co.uk/downloads/XMouseButtonControl.htm汉化语言包链接为https://www.highr......
  • Laravel 实现自定义资源路由
    Laravel如何实现自定义资源路由最近在开发过程中,发现总有一些路由需要重复定义,比如切换状态,导出,回收站啊之类的。如果使用Laravel自带的资源路由方法,还不足以满足重复劳动得过程。所以是否有方法可以自定义项目得资源路由呢?在Laravel中,资源路由一般有两种服务端渲染Route:......
  • elasticsearch初步使用学习
    通过使用elasticsearch,我们可以加快搜索时间(直接使用SQL的模糊查询搜索耗时会比较久,而且elasticsearch的响应耗时与数据量关系不大)es主要用于存储,计算,搜索数据依次部署elasticsearch,kibanadockerrun-d\--namees\-e"ES_JAVA_OPTS=-Xms512m-Xmx512m"\-e"disco......
  • 自定义表单工作流的优势介绍
    当前,应用低代码技术平台可以助力企业提高效率,降低开发成本,实现个性化场景定制,因而越来越得到了客户的信赖与喜爱。很多客户朋友询问自定义表单工作流的优势和特点,为了帮助大家解决这个疑问,今天,就跟大家一起分享低代码技术平台以及自定义表单工作流的相关知识,相信从这些字里行间中......
  • Ant Design Blazor Table 组件的 自定义分页样式, 显示全部记录数,ShowTotal
    在AntDesignBlazor中,Table 组件的 ShowTotal 属性是一个泛型属性,它可以是两种类型之一:Func<PaginationTotalContext,string> 或 RenderFragment<PaginationTotalContext>。这个属性用于定义如何显示表格数据的总条数。OneOf<T1,T2> 是一个特殊的类型,它表示这个......
  • JDK源码阅读-------自学笔记(二十六)(java.util.Map 自定义讲解)
    一、简介Map就是用来存储“键(key)-值(value)”对的.通过键寻找value,所以键不能重复.数组的本质也是一种键值对,区别就是索引一般是数字,而Map的Key可以是任意对象(字符串,数字),相当于把数组的索引范围扩的更大,使用更方便.实际开发中较为常用.二、Map的常用方法实例(1......
  • [4]自定义Lua解析器管理器-------演化脚本V0.7
    使用自定义lua解析管理器调用函数使用自定义委托来调用lua脚本中的多返回值函数和长参数类型的函数。先看代码,依旧是上篇文章中所贴的脚本。新增调用两个函数testFuncusingSystem;usingBaseFramework;usingLuaInterface;usingUnityEngine;usingUnityEngine.Events;us......
  • 自定义上传图片到服务器出现了上传失败的问题
    1、上传路径没改动这里在上传的时候发现存入路径是windows版本的//读取原始文件名StringfileName=file.getOriginalFilename();//获取后缀名StringsuffixName=fileName.substring(fileName.lastIndexOf("."));......