ES打分机制

打分机制

文档打分的运作机制:TF-IDF

Lucenees 的打分机制是一个公式。将查询作为输入,使用不同的手段来确定每一遍文档的得分,将每一个因素最后通过公式综合起来,返回该文档的最终得分。这个综合考量的过程,就是我们希望相关的文档被优先返回的考量过程。在Lucenees中这种相关性称为得分。

在开始计算得分之前,es使用了被搜索词条的频率和它有多常见来影响得分,从两个方面理解:

  • 一个词条在某篇文档中出现的次数越多,该文档就越相关
  • 一个词条如果在不同的文档中出现的次数越多,它就越不相关

词频:TF

考虑一篇文档得分的首要方式,是查看一个词条在文档中出现的次数,比如某篇围绕es的打开展开的,那么文章中肯定会多次出现相关字眼,当查询时,我们认为该文章更符合,所以,该篇文档的得分会更高。

逆文档频率:IDF

相比于词频,逆文档频率稍微显复杂,如果一个词条在索引中的不同文档出现的次数越多,那么它就越不重要

例子:

The rules-which require employees to work from 9 am to 9 pm
In the weeks that followed the creation of 996.ICU in March
The 996.ICU page was soon blocked on multiple platforms including the messaging tool WeChat and the UC Browser.

假如es索引中,有上述3篇文档:

  • 词条ICU的文档频率是2,因为它出现在2篇文章中,文档的的逆源自得分乘以1/DF,DF是该词条的文档频率,这就意味着,由于ICU 词条拥有更高的文档频率,所以,它的权重会降低。
  • 词条the的文档频率是3,它在3篇文章都出现了,注意:尽管the在后两篇文档都出现两次,但是它的词频还是3,因为,逆文档词频只检查词条是否出现在某篇文档中,而不检查它在这篇文档中出现了多少次,那是词频该干的事。

逆文档词频是一个重要的因素,用来平衡词条的词频。比如我们搜索the 996.ICU。单词the几乎出现在所有的文档中(中文中比如),如果这个不被均衡一下,那么the的频率将完全淹没996.ICU。所以,逆文档词频就有效的均衡了the这个常见词的相关性影响。以达到实际的相关性得分将会对查询的词条有一个更准确地描述。

当词频和逆文档词频计算完成,就可以使用TF-IDE公式来计算文档的得分了。

Lucene评分公

之前讨论Lucene默认评分公式被称为TF-IDF,一个基于词频和逆文档词频的公式。Lucene实用评分公式如下:
在这里插入图片描述

词条的词频越高,得分越高;相似地,索引中词条越罕见,逆文档频率越高,其中在加上商调和因子查询标准化,调和因子考虑了搜索过多少文档以及发现了多少词条;查询标准化,是试图让不同的查询结果具有可比性。我们称这种默认的打分方法时TF-IDF和向量空间模型(vector space model)的结合。

其他打分方法

除了TF-IDF结合向量空间模型的实用评分模式,是esLucene最为主流的评分机制,但这并不是唯一的,除了TF-IDF这种实用模型之外,其他的模型包括:

  • Okapi BM25
  • 随机性分歧(Divergence from randomness),即DFR相似度
  • LM Dirichlet相似度
  • LM Jelinek Mercer相似度。

这里简要的介绍BM25几种主要设置,即k1bdiscount_overlaps:

  • k1和b是数值的设置,用于调整得分是如何计算的。
  • k1控制对于得分而言词频(TF)的重要性。
  • b是介于0 ~ 1之间的数值,它控制了文档篇幅对于得分的影响程度。
  • 默认情况下,k1设置为1.2,而b则被设置为0.75
  • discount_overlaps的设置用于告诉es,在某个字段中,多少个分词出现在同一位置,是否应该影响长度的标准化,默认值是true

配置打分模型

简要配置BM25打分模型

BM25是一种基于概率的打分框架。

PUT w2
{
  "mappings": {
    "doc": {
      "properties": {
        "title": {
          "type": "text",
          "similarity": "BM25"
        }
      }
    }
  }
}

PUT w2/doc/1
{
  "title":"The rules-which require employees to work from 9 am to 9 pm"
}

PUT w2/doc/2
{
  "title":"In the weeks that followed the creation of 996.ICU in March"
}

PUT w2/doc/3
{
  "title":"The 996.ICU page was soon blocked on multiple platforms including the messaging tool WeChat and the UC Browser."
}

GET w2/doc/_search
{
  "query": {
    "match": {
      "title": "the 996"
    }
  }
}

上例是通过similarity参数来指定打分模型。只有查询,还是当数据比较大的时候

为BM25配置高级的settings

PUT w3
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer":"ik_smart"
      }
    },
    "similarity": {
      "my_custom_similarity": {
        "type": "BM25",
        "k1": 1.2,
        "b": 0.75,
        "discount_overlaps": false
      }
    }
  },
  "mappings": {
    "doc": {
      "properties": {
        "title": {
          "type": "text",
          "similarity":"my_custom_similarity"
        }
      }
    }
  }
}

PUT w3/doc/1
{
  "title":"The rules-which require employees to work from 9 am to 9 pm"
}

PUT w3/doc/2
{
  "title":"In the weeks that followed the creation of 996.ICU in March"
}

PUT w3/doc/3
{
  "title":"The 996.ICU page was soon blocked on multiple platforms including the messaging tool WeChat and the UC Browser."
}

GET w3/doc/_search
{
  "query": {
    "match": {
      "title": "the 996"
    }
  }
}

配置全局打分模型

如果我们要使用某种特定的打分模型,并且希望应用到全局,那么就在elasticsearch.yml配置文件中加入:

index.similarity.default.type: BM25

boosting

boosting是一个用来修改文档相关性的程序。boosting有两种类型:

  • 索引的时候,比如我们在定义mappings的时候
  • 查询一篇文章的时候

这两种方式都可以提升一篇文档的得分。需要注意的是:在索引期间修改文档的boosting是存储在索引中的,要想修改boosting必须重写索引该篇文档。

索引期间的boosting

PUT w4
{
  "mappings": {
    "doc": {
      "properties": {
        "name": {
          "boost": 2.0,
          "type": "text"
        },
        "age": {
          "type": "long"
        }
      }
    }
  }
}

一般不建议这样写,因为一旦映射建立完成,那么所有的name字段都会自动拥有一个boost值。要想修改这个值,那么必须重新索引文档;另外一个原因是:boost值是以降低精准度的数值存储在Lucene内部的索引结构中。只有一个字节用于存储浮点型数值(存不下就损失精度了),所以,计算文档的最终得分时可能会损失精度。最后,boost是应用与词条的。因此,再被boost的字段中如果匹配上了多个词条,就意味着计算多次的boost,这将会进一步增加字段的权重,可能会影响最终的文档的得分。

查询期间的boosting

es中,几乎所有的查询类型都支持boost,如下,在查询期间,使用match查询进行boosting

PUT w5
{
  "mappings":{
    "doc":{
      "properties": {
        "title": {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "content": {
          "type": "text",
          "analyzer": "ik_max_word"
        }
      }
    }
  }
}

PUT w5/doc/1
{
  "title":"Lucene is cool",
  "content": "Lucene is cool"
}

PUT w5/doc/2
{
  "title":"Elasticsearch builds on top of lucene",
  "content":"Elasticsearch builds on top of lucene"
}

PUT w5/doc/3
{
  "title":"Elasticsearch rocks",
  "content":"Elasticsearch rocks"
}

查询:

GET w5/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title":{
              "query": "elasticserach rocks",
              "boost": 2.5
            }
          }
        },
        {
          "match": {
            "content": "elasticserach rocks"
          }
        }
      ]
    }
  }
}

就对应最终得分而言,content字段,加了boosttitle查询更有影响力。也只有在bool查询中,boost更有意义。

跨越多个字段的查询

boost也可以用于multi_match查询

GET w5/doc/_search
{
  "query": {
    "multi_match": {
      "query": "elasticserach rocks",
      "fields": ["title", "content"],
      "boost": 2.5
    }
  }
}

除此之外,我们还可以使用特殊的语法,只为特定的字段指定一个boost。通过在字段名称后添加一个^符号和boost的值。告诉es只需要对那个字段进行boost

GET w5/doc/_search
{
  "query": {
    "multi_match": {
      "query": "elasticserach rocks",
      "fields": ["title^3", "content"]
    }
  }
}

上例中,title字段被boost了3被。

需要注意的是:在使用boost的时候,无论是字段或者词条,都是按照相对值来boost的,而不是乘以乘数。如果对于所有的待搜索词条boost了同样的值,那么就像没有boost一样。因为Luncene会标准化boost的值。如果boost一个字段的4倍,不是意味着该字段的得分就是乘以4的结果。

Elasticsearch 是一个基于 Lucene 的分布式、RESTful 搜索和分析引擎,其核心检索机制围绕**倒排索引(Inverted Index)**和**分布式查询处理**展开。以下是其检索机制和使用方法的详细说明: --- ### **1. Elasticsearch 检索机制** #### **(1)倒排索引(Inverted Index)** - **核心原理**: - 将文档(Document)拆分为**词项(Term)**,并记录每个词项出现在哪些文档中(类似字典的“词→文档列表”映射)。 - 例如:文档1包含“苹果 香蕉”,文档2包含“苹果 橙子”,倒排索引为: ``` 苹果 → [文档1, 文档2] 香蕉 → [文档1] 橙子 → [文档2] ``` - **优势**: - 快速定位包含特定词项的文档,避免全表扫描。 - 支持高效布尔查询(AND/OR/NOT)。 #### **(2)分布式查询处理** - **分片(Shard)**: - 索引(Index)被划分为多个分片(默认5个主分片),分布在集群的不同节点上。 - 查询时,协调节点(Coordinating Node)将请求广播到所有相关分片,并行处理后合并结果。 - **流程**: 1. 用户发送查询请求到任意节点(协调节点)。 2. 协调节点确定查询涉及的分片,并转发请求。 3. 各分片本地执行查询,返回结果(含文档ID和评分)。 4. 协调节点合并结果,按相关性排序后返回。 #### **(3)相关性评分(TF-IDF & BM25)** - **TF-IDF**: - 词频(TF):词项在文档中出现的频率。 - 逆文档频率(IDF):词项在所有文档中的稀有程度(常见词权重低)。 - **BM25(默认算法)**: - 改进TF-IDF,考虑文档长度、词项频率饱和度等因素,评分更精准。 - **示例**: - 查询“苹果 手机”时,同时包含两个词的文档评分更高。 #### **(4)实时性与近实时(NRT)** - **倒排索引不可变**: - 新增文档写入新索引段(Segment),定期合并(Merge)到主索引。 - **近实时(NRT)**: - 文档写入后约1秒可被搜索(通过`refresh_interval`配置,默认1秒)。 - 完全持久化需`flush`操作(将内存数据刷到磁盘)。 --- ### **2. Elasticsearch 使用方法** #### **(1)基础操作** ##### **① 索引文档** ```json PUT /products/_doc/1 { "name": "iPhone 13", "price": 799, "description": "高性能智能手机", "tags": ["苹果", "手机"] } ``` - **说明**: - `products`:索引名(类似数据库表)。 - `_doc`:类型(7.x+版本默认单类型)。 - `1`:文档ID(可省略,自动生成)。 ##### **② 简单查询** ```json GET /products/_search { "query": { "match": { "name": "iPhone" } } } ``` - **返回结果**: ```json { "hits": { "hits": [ { "_id": "1", "_score": 0.2876821, // BM25评分 "_source": { "name": "iPhone 13", "price": 799 } } ] } } ``` ##### **③ 布尔查询(AND/OR/NOT)** ```json GET /products/_search { "query": { "bool": { "must": [ { "match": { "tags": "苹果" } } ], "filter": [ { "range": { "price": { "lte": 1000 } } } // 价格≤1000 ] } } } ``` #### **(2)高级功能** ##### **① 全文检索(分析文本)** - **分词器(Analyzer)**: - 默认使用`standard`分词器(按空格分词,小写化)。 - 自定义分词器示例: ```json PUT /my_index { "settings": { "analysis": { "analyzer": { "my_analyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "asciifolding"] // 小写+去除重音 } } } } } ``` ##### **② 聚合查询(Aggregation)** ```json GET /products/_search { "size": 0, // 不返回文档,仅聚合结果 "aggs": { "avg_price": { "avg": { "field": "price" } }, "tags_count": { "terms": { "field": "tags.keyword" } // 对精确值聚合 } } } ``` - **结果**: ```json { "aggregations": { "avg_price": { "value": 799 }, "tags_count": { "buckets": [ { "key": "苹果", "doc_count": 1 }, { "key": "手机", "doc_count": 1 } ] } } } ``` ##### **③ 高亮显示(Highlight)** ```json GET /products/_search { "query": { "match": { "description": "智能" } }, "highlight": { "fields": { "description": {} } } } ``` - **返回结果**: ```json { "hits": { "hits": [ { "_source
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值