ElasticSearch打分机制学习

创建一个索引

curl -s -XPUT 'http://localhost:9200/gino_test/' -d '{
  "mappings": {
    "tweet": {
      "properties": {
        "text": {
          "type": "string",
          "term_vector": "with_positions_offsets_payloads",
          "store" : true,
          "analyzer" : "fulltext_analyzer"
         },
         "fullname": {
          "type": "string",
          "term_vector": "with_positions_offsets_payloads",
          "analyzer" : "fulltext_analyzer"
        }
      }
    }
  },
  "settings" : {
    "index" : {
      "number_of_shards" : 1,
      "number_of_replicas" : 0
    },
    "analysis": {
      "analyzer": {
        "fulltext_analyzer": {
          "type": "custom",
          "tokenizer": "whitespace",
          "filter": [
            "lowercase",
            "type_as_payload"
          ]
        }
      }
    }
  }
}'

插入测试数据:

_index_type_idtextfullname
gino_testtweet1hello worldgino zhang
gino_testtweet2gino like world cupgino li
gino_testtweet3my cupjsper li

简单情况:单字段匹配打分

POST http://192.168.102.216:9200/gino_test/_search
{
  "explain": true,
  "query": {
    "match": {
      "text": "my cup"
    }
  }
}

查询结果: score_example1.json https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220B4dv03yigoV2VjFIbEI3ZFQwRlk%22]}

打分分析:
https://drive.google.com/open?id=1RZhu9j9NNy30KNYd4qwQ9b6o5utdnyq0yqzDhdW_5uo
example1_1.jpg

https://drive.google.com/open?id=1B4fVZLiGvHAIrKH_zk7jTSVHjcXQC1Byd8tKXbNswck
example1_2.jpg

score(q,d)  =  queryNorm(q)  · coord(q,d)  · ∑ (tf(t,d) · idf(t)² · t.getBoost() · norm(t,d))    
  • score(q,d) is the relevance score of document d for query q.
  • queryNorm(q) is the query normalization factor (new).
  • coord(q,d) is the coordination factor (new).
  • The sum of the weights for each term t in the query q for document d.
  • tf(t,d) is the term frequency for term t in document d.
  • idf(t) is the inverse document frequency for term t.
  • t.getBoost() is the boost that has been applied to the query (new).
  • norm(t,d) is the field-length norm, combined with the index-time field-level boost, if any. (new).
    You should recognize score, tf, and idf. The queryNorm, coord, t.getBoost, and norm are new.

注意:在计算过程中,涉及的变量应该考虑的是document所在的分片而不是整个index。

score(q,d) = _score(q,d.f)                                               --------- ①
= queryNorm(q) · coord(q,d) · ∑ (tf(t,d) · idf(t)² · t.getBoost() · norm(t,d))
= coord(q,d) · ∑ (tf(t,d) · idf(t)² · t.getBoost() · norm(t,d) · queryNorm(q))
= coord(q,d.f) · ∑ _score(q.ti, d.f) [ti in q]                           --------- ②
= coord(q,d.f) · (_score(q.t1, d.f) + _score(q.t2, d.f))
  • ① 相关性打分其实是查询与某个文档的某个字段之间的相关性打分,而不是与文档的相关性;
  • ② 根据公式转换,就变成了查询的所有Term与文档中字段的相关性求和,如果某个Term不相关,则需要处理coord系数;

multi-match多字段匹配打分(best_fields模式)

POST http://192.168.102.216:9200/gino_test/_search
{
  "explain": true,
  "query": {
    "multi_match": {
      "query": "gino cup",
      "fields": [
        "text^8",
        "fullname^5"
      ]
    }
  }
}

查询结果:score_example2.json
https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220B4dv03yigoV2MTdsWHFqRGRsZUU%22]}

打分分析:

score(q,d) = max(_score(q, d.fi)) = max(_score(q, d.f1), _score(q, d.f2))
= max(coord(q,d.f1) · (_score(q.t1, d.f1) + _score(q.t2, d.f1)), coord(q,d.f2) · (_score(q.t1, d.f2) + _score(q.t2, d.f2)))
  • 对于multi-field的best_fields模式来说,相当于是对每个字段对查询分别进行打分,然后执行max运算获取打分最高的。
  • 在计算query weight的过程需要乘上字段的权重,在计算fieldNorm的时候也需要乘上字段的权重。
  • 默认operator为or,如果使用and,打分机制也是一样的,但是搜索结果会不一样。

multi-match多字段匹配打分(cross_fields模式)

POST http://192.168.102.216:9200/gino_test/_search
{
  "explain": true,
  "query": {
    "multi_match": {
      "query": "gino cup",
      "type": "cross_fields",
      "fields": [
        "text^8",
        "fullname^5"
      ]
    }
  }
}

查询结果:score_example3.json
https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220B4dv03yigoV2OU40bWp1ZnlsT00%22]}

打分分析:

score(q, d) = ∑ (_score(q.ti, d.f)) = ∑ (_score(q.t1, d.f), _score(q.t1, d.f))
= ∑ (max(coord(q.t1,d.f) · _score(q.t1, d.f1), coord(q.t1,d.f) · _score(q.t1, d.f2)), max(coord(q.t2,d.f) · _score(q.t2, d.f1), coord(q.t2,d.f) · _score(q.t2, d.f2)))
  • coord(q.t1,d.f)函数表示搜索的Term(如gino)在multi-field中有多少比率的字段匹配到;best_fields模式中coord(q,d.f1)表示搜索的所以Term(如gino和cup)有多少比率存在与特定的field字段(如text字段)里;
  • 对于multi-field的cross_fields模式来说,相当于是对每个查询的Term进行打分(每个Term执行best_fields打分,即看下哪个field匹配更高),然后执行sum运算。
  • 默认operator为or,如果使用and,打分机制也是一样的,但是搜索结果会不一样。score_example4.json
    https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220B4dv03yigoV2SDFGSEFJNWVBZU0%22]}

should增加权重打分

为了增加filter的测试,给gino_test/tweet增加一个tags的字段。

PUT /gino_test/_mapping/tweet
{
  "properties": {
    "tags": {
      "type": "string",
      "analyzer": "fulltext_analyzer"
    }
  }
}

增加tags的标签

_index_type_idtextfullnametags
gino_testtweet1hello worldgino zhangnew, gino
gino_testtweet2gino like world cupgino lihobby, gino
gino_testtweet3my cupjsper ligoods, jasper

POST http://192.168.102.216:9200/gino_test/_search
{
“explain”: true,
“query”: {
“bool”: {
“must”: {
“bool”: {
“must”: {
“multi_match”: {
“query”: “gino cup”,
“fields”: [
“text^8”,
“fullname^5”
],
“type”: “best_fields”,
“operator”: “or”
}
},
“should”: [
{
“term”: {
“tags”: {
“value”: “goods”,
“boost”: 6
}
}
},
{
“term”: {
“tags”: {
“value”: “hobby”,
“boost”: 3
}
}
}
]
}
}
}
}
}

查询结果:score_example5.json https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220B4dv03yigoV2TFZQREgzdHh2NmM%22]}

打分分析:
https://drive.google.com/open?id=10N-3DTBwkQvtjeegocbEH4jiQWn9PFterM3BYUyzh5Q
example5.jpg

  • 增加了should的权重之后,相当于多了一个打分参考项,打分的过程见上面的计算过程。

function_score高级打分机制

DSL格式:

{
    "function_score": {
        "query": {},
        "boost": "boost for the whole query",
        "functions": [
            {
                "filter": {},
                "FUNCTION": {}, 
                "weight": number
            },
            {
                "FUNCTION": {} 
            },
            {
                "filter": {},
                "weight": number
            }
        ],
        "max_boost": number,
        "score_mode": "(multiply|max|...)",
        "boost_mode": "(multiply|replace|...)",
        "min_score" : number
    }
}

支持四种类型发FUNCTION:
- script_score: 自定义的高级打分机制,涉及的字段只能是数值类型的
- weight: 权重打分,一般结合filter一起使用,表示满足某种条件加多少倍的分
- random_score: 生成一个随机分数,比如应该uid随机打乱排序
- field_value_factor: 根据index里的某个字段值影响打分,比如销量(涉及的字段只能是数值类型的)
- decay functions: 衰减函数打分,比如越靠近市中心的打分越高

来做一个实验。先给index增加一个查看数的字段:

PUT /gino_test/_mapping/tweet
{
  "properties": {
    "views": {
      "type": "long",
      "doc_values": true,
      "fielddata": {
        "format": "doc_values"
    }
  }
}

给三条数据分别加上查看数的值:

POST gino_test/tweet/1/_update
{
    "doc" : {
        "views" : 56
    }
}

最终数据的样子:

_index_type_idtextfullnametagsviews
gino_testtweet1hello worldgino zhangnew, gino56
gino_testtweet2gino like world cupgino lihobby, gino21
gino_testtweet3my cupjsper ligoods, jasper68

执行一个查询:

{
  "explain": true,
  "query": {
    "function_score": {
      "query": {
        "multi_match": {
          "query": "gino cup",
          "type": "cross_fields",
          "fields": [
            "text^8",
            "fullname^5"
          ]
        }
      },
      "boost": 2,
      "functions": [
        {
          "field_value_factor": {
            "field": "views",
            "factor": 1.2,
            "modifier": "sqrt",
            "missing": 1
          }
        },
        {
          "filter": {
            "term": {
              "tags": {
                "value": "goods"
              }
            }
          },
          "weight": 4
        }
      ],
      "score_mode": "multiply",
      "boost_mode": "multiply"
    }
  }
}

查询结果:score_example6.json https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220B4dv03yigoV2MlRXU0xUUkdDZEU%22]}

打分分析:

score(q,d) = score_query(q,d) * (score_fvf(`view`) * score_filter(`tags:goods`))
  • score_mode表示多个FUNCTION之间打分的运算法则,需要注意不同的FUNCTION的打分的结果级别可能相差很大;
  • boost_mode表示function_score和query_score打分的运算法则,也需要注意打分结果的级别;

rescore重打分机制

ES官网介绍: https://www.elastic.co/guide/en/elasticsearch/reference/2.3/search-request-rescore.html

重打分机制并不会应用到所有的数据中。比如需要查询前10条数据,那么所有的分片先按默认规则查询出前10条数据,然后应用rescore规则进行重打分返回给master节点进行综合排序返回给用户。

rescore支持多个规则计算,以及与原先的默认打分进行运算(权重求和等)。

rescore因为计算的打分的document较少,性能应该会更好一点,但是这个涉及到全局排序,实际运用的场景要注意。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你好!关于学习Elasticsearch,我可以给你一些指导。Elasticsearch是一个开源的分布式搜索和分析引擎,主要用于快速、实时地存储、搜索和分析大量数据。下面是一些学习Elasticsearch的步骤: 1. 了解基本概念:开始学习Elasticsearch之前,你需要了解一些基本的概念,比如索引(index)、类型(type)、文档(document)、字段(field)等。这将帮助你更好地理解Elasticsearch的工作原理。 2. 安装和配置:根据你的操作系统,你可以从Elasticsearch官方网站下载并安装合适的版本。安装完成后,你需要进行适当的配置,如设置集群名称、分配内存等。 3. 学习REST API:Elasticsearch提供了丰富的REST API,用于与其进行交互。了解如何使用这些API来索引、搜索和删除数据学习Elasticsearch的重要一步。 4. 索引和搜索数据学习如何创建索引、添加文档以及执行搜索操作是使用Elasticsearch的关键。掌握查询语法、过滤器、聚合操作等功能可以帮助你更有效地使用Elasticsearch。 5. 数据建模和分析:学习如何设计合适的数据模型和映射,以及如何使用Elasticsearch进行数据分析和可视化是提高你的技能的重要一步。 6. 扩展和优化:学习如何在生产环境中扩展和优化Elasticsearch集群是非常重要的。了解如何分片、复制、调优性能等将帮助你更好地管理和维护你的数据。 7. 学习资源:除了官方文档,还有很多优秀的学习资源可供参考,如书籍、教程和在线课程等。利用这些资源可以更系统地学习和掌握Elasticsearch。 希望这些步骤能对你学习Elasticsearch有所帮助!如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值