Elasticsearch:Rank feature query

2022年1月13日   |   by mebius

在我之前的文章:

我运用了distance_feature来针对位置和时间来对搜素的文档进行加权。它们在实际的使用中非常有用。比如我们搜索新闻,我们首先肯定对最近发生的事非常感兴趣,我们希望搜索的结果把最近的文档排在前面的位置。当我们搜索一样东西时,我们希望把靠近我们位置的文档排在搜索结果的前面,比如附近的餐馆,虽然索引里可能有两个同样名称的餐馆。

那么在实际的使用中,假如有一个索引的字段是数值,那么我们有什么方法通过同样的方法来进行加权呢?比如,我们想把没有参加过拍卖的文档排在前面,这样更容易让那些没有参加过拍卖的文档更加容易曝光。

实现这种需求的方法就是使用 Rank feature query

Rank feature query 介绍

根据 rank_featurerank_features 字段的数值提高文档的相关性分数

rank_feature 查询通常用在 bool 查询的 should 子句中,因此它的相关性分数被添加到 bool 查询的其他分数中。

将 rank_feature 或 rank_features 字段的 positive_score_impact 设置为 false,我们建议参与查询的每个文档都具有该字段的值。否则,如果在 should 子句中使用了 rank_feature 查询,它不会向具有缺失值的文档的分数添加任何内容,但会为包含特征的文档添加一些提升。这与我们想要的相反 — 因为我们认为这些特征是负面的,我们希望包含它们的文档的排名低于缺少它们的文档。在下面的例子中,我们将进一步进行展示。

与 function_score 查询或其他更改相关性分数的方法不同,rank_feature 查询在 track_total_hits 参数不为 true 时有效地跳过非竞争性 hits。这可以显着提高查询速度。

Rank feature functions

为了根据排名特征字段计算相关性分数,rank_feature 查询支持以下数学函数:

如果你不知tgcode道从哪里开始,我们建议你使用 saturation 函数。 如果没有提供函数,rank_feature 查询默认使用 saturation 函数。

示例

要使用 rank_feature 查询,你的索引必须包含 rank_featurerank_features 字段映射。 要了解如何为 rank_feature 查询设置索引,请尝试以下示例。

使用以下字段映射创建 test 索引:

  • pagerank,一个 rank_feature 字段,用于衡量网站的重要性
  • url_length,一个 rank_feature 字段,其中包含网站 URL 的长度。 对于此示例,长 URL 与相关性呈负相关,也就是说,长度越长,相关性越差,最终的分数越小。由 positive_score_impact 值为 false 表示。
  • topics,一个 rank_features 字段,其中包含 topic 列表和衡量每个文档与该 topic 的联系程度的度量

我们首先来创建一个如下的一个 test 索引:

PUT /test
{
  "mappings": {
    "properties": {
      "pagerank": {
        "type": "rank_feature"
      },
      "url_length": {
        "type": "rank_feature",
        "positive_score_impact": false
      },
      "topics": {
        "type": "rank_features"
      }
    }
  }
}

在上面,我们定义了 pagerank,url_length 及 topics 字段。它们分别是 rank_feauture, rank_feauture 及 rank_features 类型的字段。

我们接着使用如下的方法来写入几个文档:

PUT /test/_doc/1?refresh
{
  "url": "https://en.wikipedia.org/wiki/2016_Summer_Olympics",
  "content": "Rio 2016",
  "pagerank": 50.3,
  "url_length": 42,
  "topics": {
    "sports": 50,
    "brazil": 30
  }
}

PUT /test/_doc/2?refresh
{
  "url": "https://en.wikipedia.org/wiki/2016_Brazilian_Grand_Prix",
  "content": "Formula One motor race held on 13 November 2016",
  "pagerank": 60.3,
  "url_length": 47,
  "topics": {
    "sports": 35,
    "formula one": 65,
    "brazil": 20
  }
}

PUT /test/_doc/3?refresh
{
  "url": "https://en.wikipedia.org/wiki/Deadpool_(film)",
  "content": "Deadpool is a 2016 American superhero film",
  "pagerank": 70.3,
  "url_length": 37,
  "topics": {
    "movies": 60,
    "super hero": 65
  }
}

从上面的文档中,我们可以看出来,虽然 pagerank 被定义为 rank_feauture 类型,但是它的实际值为浮点数类型的。

我们首先来做如下的搜索:

GET /test/_search?filter_path=**hits
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "2016"
          }
        }
      ],
      "should": [
        {
          "rank_feature": {
            "field": "pagerank"
          }
        }
      ]
    }
  }
}

我们的搜索结果如下:

{
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.6440702,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.6440702,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/Deadpool_(film)",
          "content" : "Deadpool is a 2016 American superhero film",
          "pagerank" : 70.3,
          "url_length" : 37,
          "topics" : {
            "movies" : 60,
            "super hero" : 65
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5969556,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Summer_Olympics",
          "content" : "Rio 2016",
          "pagerank" : 50.3,
          "url_length" : 42,
          "topics" : {
            "sports" : 50,
            "brazil" : 30
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.59679806,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Brazilian_Grand_Prix",
          "content" : "Formula One motor race held on 13 November 2016",
          "pagerank" : 60.3,
          "url_length" : 47,
          "topics" : {
            "sports" : 35,
            "formula one" : 65,
            "brazil" : 20
          }
        }
      }
    ]
  }

上面的搜索结果对我们来说,看起来不是很明显。我们再做一个不含 should 的搜索:

GET /test/_search?filter_path=**hits
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "2016"
          }
        }
      ]
    }
  }
}

上面搜索的结果为:

{
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.18360566,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.18360566,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Summer_Olympics",
          "content" : "Rio 2016",
          "pagerank" : 50.3,
          "url_length" : 42,
          "topics" : {
            "sports" : 50,
            "brazil" : 30
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.12500812,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/Deadpool_(film)",
          "content" : "Deadpool is a 2016 American superhero film",
          "pagerank" : 70.3,
          "url_length" : 37,
          "topics" : {
            "movies" : 60,
            "super hero" : 65
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.110856235,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Brazilian_Grand_Prix",
          "content" : "Formula One motor race held on 13 November 2016",
          "pagerank" : 60.3,
          "url_length" : 47,
          "topics" : {
            "sports" : 35,
            "formula one" : 65,
            "brazil" : 20
          }
        }
      }
    ]
  }
}

对于上面的搜索分数,大家可能不会太陌生。因为所有的三个文档都含有 2016,所以所有的三个文档都会被正确地搜索出来,但是由于 id 为 “1” 的文档更短,所以具有更高的分数。同样 id 为 “2” 的文档长度也较短,所以排名第二。关于如何计算分数,请参考我的文章 “Elasticsearch:分布式计分”。

这个结果和我们之前添加 should 后的搜索的进行比较,由于引进了 should,我们搜索结果的排序发生了变化。从 1,3,2 变为 3,1,2 的顺序。这个结果是可以理解的。这是因为引入了 should,而在它里面使用了 rank_feature 查询。在默认的情况下,positive_score_impact 为 ture,也就意味着 pagerank 值越大,那么代表越相关。在我们的三个文档中,id 为 “3” 的 pagerank 值最大,所以它帮助整个搜索进行分数的提升。

事实上,我们甚至可以添加 boost 参数来提升这个 rank_feature 的重要性:

GET /test/_search?filter_path=**hits
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "2016"
          }
        }
      ],
      "should": [
        {
          "rank_feature": {
            "field": "pagerank",
            "boost": 2.0
          }
        }
      ]
    }
  }
}

在上面,我们添加了 boost 参数,并且把这个参数值提高为 2.0,那么上面的搜索结果为:

{
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.2109984,
    "hits" :tgcode [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.2109984,
        "_source" : {
          "url" : "https://en.wikipedia.tgcodeorg/wiki/Deadpool_(film)",
          "content" : "Deadpool is a 2016 American superhero film",
          "pagerank" : 70.3,
          "url_length" : 37,
          "topics" : {
            "movies" : 60,
            "super hero" : 65
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.1202803,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Brazilian_Grand_Prix",
          "content" : "Formula One motor race held on 13 November 2016",
          "pagerank" : 60.3,
          "url_length" : 47,
          "topics" : {
            "sports" : 35,
            "formula one" : 65,
            "brazil" : 20
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.1024628,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Summer_Olympics",
          "content" : "Rio 2016",
          "pagerank" : 50.3,
          "url_length" : 42,
          "topics" : {
            "sports" : 50,
            "brazil" : 30
          }
        }
      }
    ]
  }
}

我们可看到最终得到的分数是按照 pagerank 进行降序排列的。这充分说明了 rank_feature 在搜索中确实起到了作业。

在实际的使用中,我们有时并不希望数值越大则代表相关性越强。比如,我们认为,数值越小,它代表相关性越强。就像我在文章开始介绍的那样。我们有时想对那些没有参加过拍卖的文档进行加分。在本例子中,我们认为 url_length 越小,则代表相关性越强。针对这种情况,我们必须设置positive_score_impact 为 false。

我们进行如下的搜索:

GET /test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "2016"
          }
        }
      ],
      "should": [
        {
          "rank_feature": {
            "field": "url_length",
            "boost": 3.0
          }
        }
      ]
    }
  }
}

上面搜索的结果为:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.7130321,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.7130321,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/Deadpool_(film)",
          "content" : "Deadpool is a 2016 American superhero film",
          "pagerank" : 70.3,
          "url_length" : 37,
          "topics" : {
            "movies" : 60,
            "super hero" : 65
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.6778586,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Summer_Olympics",
          "content" : "Rio 2016",
          "pagerank" : 50.3,
          "url_length" : 42,
          "topics" : {
            "sports" : 50,
            "brazil" : 30
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.519763,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Brazilian_Grand_Prix",
          "content" : "Formula One motor race held on 13 November 2016",
          "pagerank" : 60.3,
          "url_length" : 47,
          "topics" : {
            "sports" : 35,
            "formula one" : 65,
            "brazil" : 20
          }
        }
      }
    ]
  }
}

从上面的搜索结果中,我们可以看出来文档的排序为:3,1,2, 而对应于它们的 url_length 值分别为:37,42,47。排名的顺序是按照 url_length 的值进行升序进行排列的,也就是说 url_length 值越小,则代表相关性越大。

最后,我们可以结合 rank_features 进行查询:

GET /test/_search?filter_path=**hits
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "2016"
          }
        }
      ],
      "should": [
        {
          "rank_feature": {
            "field": "pagerank"
          }
        },
        {
          "rank_feature": {
            "field": "url_length",
            "boost": 0.1
          }
        },
        {
          "rank_feature": {
            "field": "topics.sports",
            "boost": 0.4
          }
        }
      ]
    }
  }
}

在上面,我们使用 topics.sports 这样的形式来访问 rank_feautures 里的项。上面搜索的结果为:

{
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.90905887,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.90905887,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Summer_Olympics",
          "content" : "Rio 2016",
          "pagerank" : 50.3,
          "url_length" : 42,
          "topics" : {
            "sports" : 50,
            "brazil" : 30
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.843177,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/2016_Brazilian_Grand_Prix",
          "content" : "Formula One motor race held on 13 November 2016",
          "pagerank" : 60.3,
          "url_length" : 47,
          "topics" : {
            "sports" : 35,
            "formula one" : 65,
            "brazil" : 20
          }
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.7209374,
        "_source" : {
          "url" : "https://en.wikipedia.org/wiki/Deadpool_(film)",
          "content" : "Deadpool is a 2016 American superhero film",
          "pagerank" : 70.3,
          "url_length" : 37,
          "topics" : {
            "movies" : 60,
            "super hero" : 65
          }
        }
      }
    ]
  }
}

上面的搜索结果其实也蛮容易理解的。由于文档 “3” 里不含有 topics.sports,所以它的得分最低。在通用的情况下,由于文档 “1” 里的 content 文本长度最短,从而使得它的分数也最高。

文章来源于互联网:Elasticsearch:Rank feature query

相关推荐: Elastic:使用 Elastic Stack 来监督 Apache 日志及指标

在我之前的许多文章中,我基本上都已经讲到了这些方面的内容。在今天的文章中,我想针对一些开发还没有自己的系统,比如 centos 或 Ubuntu OS 来写一篇非常详细的文章。在这篇文章中,我将详述: 使用 Docker 安装 Elastic Stack:El…

Tags: