如何让一个文档在搜索结果中永远排第一名

原创
05/26 08:00
阅读数 38

导语



在许多的情况下,我们需要把想要的文档的排名排在第一。比如对于 eCommerce 的用户来说,我想把某个或某些商品的排名提高,这样它们永远排在其它的文档的前面。对于一些讨论区,我想把某些帖子永远置顶。又或者说,某些搜索网站,由于客户给的钱多,我想把他们的广告永远放到搜索结果的第一页的第一个位置。这个叫做竞价排名。


在我之前的文章 “Elasticsearch: 运用 Pinned query 来提高文档的排名 (7.5发行版新功能)”,我介绍了一种使用 Pinneed query 的方法来针对一些 id 来进行处理从而使得它们的排名靠前。这个在很多的场合是非常有用的。前提条件是我们需要知道它们的 id,另外这个功能也只适合在 7.5 发现的版本之后。


在今天的文章中,我来介绍一种比较通用的办法:使用 script 来进行排序。当然使用 script 的坏处是:针对大量数据来说,它需要针对每个文档进行计算,会带来一些计算的损耗。


准备数据


在今天的练习中,我们使用如下的数据:

POST _bulk{ "index" : { "_index" : "twitter", "_id": 1} }{"user":"张三","message":"今儿天气不错啊,出去转转去","uid":"1","city":"北京","province":"北京","country":"中国","address":"中国北京市海淀区","location":{"lat":"39.970718","lon":"116.325747"}, "DOB":"1980-12-01"}{ "index" : { "_index" : "twitter", "_id": 2 }}{"user":"老刘","message":"出发,下一站云南!","uid":"2", "city":"北京","province":"北京","country":"中国","address":"中国北京市东城区台基厂三条3号","location":{"lat":"39.904313","lon":"116.412754"}, "DOB":"1981-12-01"}{ "index" : { "_index" : "twitter", "_id": 3} }{"user":"李四","message":"happy birthday!","uid":"3","city":"北京","province":"北京","country":"中国","address":"中国北京市东城区","location":{"lat":"39.893801","lon":"116.408986"}, "DOB":"1982-12-01"}{ "index" : { "_index" : "twitter", "_id": 4} }{"user":"老贾","message":"123,gogogo","uid":"4","city":"北京","province":"北京","country":"中国","address":"中国北京市朝阳区建国门","location":{"lat":"39.718256","lon":"116.367910"}, "DOB":"1983-12-01"}{ "index" : { "_index" : "twitter", "_id": 5} }{"user":"老王","message":"Happy BirthDay My Friend!","uid":"5","city":"北京","province":"北京","country":"中国","address":"中国北京市朝阳区国贸","location":{"lat":"39.918256","lon":"116.467910"}, "DOB":"1984-12-01"}{ "index" : { "_index" : "twitter", "_id": 6} }{"user":"老吴","message":"好友来了都今天我生日,好友来了,什么 birthday happy 就成!","uid":"6","city":"上海","province":"上海","country":"中国","address":"中国上海市闵行区","location":{"lat":"31.175927","lon":"121.383328"}, "DOB":"1985-12-01"}


对数据进行搜索


首先我们想查询所有在北京的用户:

GET twitter/_search{  "query": {    "match": {      "city": "北京"    }  }}


我们执行上面的搜索,得到如下的结果:

{  "took" : 0,  "timed_out" : false,  "_shards" : {    "total" : 1,    "successful" : 1,    "skipped" : 0,    "failed" : 0  },  "hits" : {    "total" : {      "value" : 5,      "relation" : "eq"    },    "max_score" : 0.48232412,    "hits" : [      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "1",        "_score" : 0.48232412,        "_source" : {          "user" : "张三",          "message" : "今儿天气不错啊,出去转转去",          "uid" : "1",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市海淀区",          "location" : {            "lat" : "39.970718",            "lon" : "116.325747"          },          "DOB" : "1980-12-01"        }      },      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "2",        "_score" : 0.48232412,        "_source" : {          "user" : "老刘",          "message" : "出发,下一站云南!",          "uid" : "2",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市东城区台基厂三条3号",          "location" : {            "lat" : "39.904313",            "lon" : "116.412754"          },          "DOB" : "1981-12-01"        }      },      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "3",        "_score" : 0.48232412,        "_source" : {          "user" : "李四",          "message" : "happy birthday!",          "uid" : "3",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市东城区",          "location" : {            "lat" : "39.893801",            "lon" : "116.408986"          },          "DOB" : "1982-12-01"        }      },      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "4",        "_score" : 0.48232412,        "_source" : {          "user" : "老贾",          "message" : "123,gogogo",          "uid" : "4",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市朝阳区建国门",          "location" : {            "lat" : "39.718256",            "lon" : "116.367910"          },          "DOB" : "1983-12-01"        }      },      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "5",        "_score" : 0.48232412,        "_source" : {          "user" : "老王",          "message" : "Happy BirthDay My Friend!",          "uid" : "5",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市朝阳区国贸",          "location" : {            "lat" : "39.918256",            "lon" : "116.467910"          },          "DOB" : "1984-12-01"        }      }    ]  }}


从上面我们可以看出来:uid 为1的文档排在第一的位置,尽管它和其它文档的分数都是一样的。


接下来,我们想把 uid 为2和3的文档的得分提高,想让它们在搜索结果中排在前面的位置,那么我们该如何做到呢?我们可以使用如下的方法:

GET twitter/_search{  "query": {    "match": {      "city": "北京"    }  },  "sort": [    {      "_script": {        "type": "number",        "script": {          "source": "Boolean.compare(params.ids.contains(doc['uid.keyword'].value), false);",          "lang": "painless",          "params": {            "ids": [              "2",              "3"            ]          }        },        "order": "desc"      }    },    {      "_score": {        "order": "desc"      }    }  ]}


在上面,我使用了一个 script 的脚本来重新计算一个 number,并按照它来进行排序。在 ids 中,我们定义了文档的 uid 值。这是一个数组。我们可以把想提高排名的 uid 值填入这个数组中,从而达到使得它们的排名靠前。


上面搜索的运行结果为:

{  "took" : 0,  "timed_out" : false,  "_shards" : {    "total" : 1,    "successful" : 1,    "skipped" : 0,    "failed" : 0  },  "hits" : {    "total" : {      "value" : 5,      "relation" : "eq"    },    "max_score" : null,    "hits" : [      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "2",        "_score" : 0.48232412,        "_source" : {          "user" : "老刘",          "message" : "出发,下一站云南!",          "uid" : "2",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市东城区台基厂三条3号",          "location" : {            "lat" : "39.904313",            "lon" : "116.412754"          },          "DOB" : "1981-12-01"        },        "sort" : [          1.0,          0.48232412        ]      },      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "3",        "_score" : 0.48232412,        "_source" : {          "user" : "李四",          "message" : "happy birthday!",          "uid" : "3",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市东城区",          "location" : {            "lat" : "39.893801",            "lon" : "116.408986"          },          "DOB" : "1982-12-01"        },        "sort" : [          1.0,          0.48232412        ]      },      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "1",        "_score" : 0.48232412,        "_source" : {          "user" : "张三",          "message" : "今儿天气不错啊,出去转转去",          "uid" : "1",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市海淀区",          "location" : {            "lat" : "39.970718",            "lon" : "116.325747"          },          "DOB" : "1980-12-01"        },        "sort" : [          0.0,          0.48232412        ]      },      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "4",        "_score" : 0.48232412,        "_source" : {          "user" : "老贾",          "message" : "123,gogogo",          "uid" : "4",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市朝阳区建国门",          "location" : {            "lat" : "39.718256",            "lon" : "116.367910"          },          "DOB" : "1983-12-01"        },        "sort" : [          0.0,          0.48232412        ]      },      {        "_index" : "twitter",        "_type" : "_doc",        "_id" : "5",        "_score" : 0.48232412,        "_source" : {          "user" : "老王",          "message" : "Happy BirthDay My Friend!",          "uid" : "5",          "city" : "北京",          "province" : "北京",          "country" : "中国",          "address" : "中国北京市朝阳区国贸",          "location" : {            "lat" : "39.918256",            "lon" : "116.467910"          },          "DOB" : "1984-12-01"        },        "sort" : [          0.0,          0.48232412        ]      }    ]  }}


从上面的返回结果中,我们可以看出来 uid 为 2 和 3 的文档排名靠前。它们出现在搜索结果的最前面。



正文完



 作者:刘晓国

本文编辑:喝咖啡的猫



嗨,互动起来吧!

喜欢这篇文章么?

欢迎留下你想说的,留言 100% 精选哦!

Elastic 社区公众号长期征稿,如果您有 Elastic  技术的相关文章,也欢迎投稿至本公众号,一起进步! 投稿请添加微信:medcl123



招聘信息

Job board


社区招聘栏目是一个新的尝试,帮助社区的小伙伴找到心仪的职位,也帮助企业找到所需的人才,为伯乐和千里马牵线搭桥。有招聘需求的企业和正在求职的社区小伙伴,可以联系微信 medcl123 提交招聘需求和发布个人简历信息。


Elastic中文社区公众号 (elastic-cn)

为您汇集 Elastic 社区的最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等。

喜欢本篇内容就请给我们点个[在看]吧




本文分享自微信公众号 - Elastic中文社区(elastic-cn)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部