ES中如何实现对查询结果的二次排序

简介: ES中如何实现对查询结果的二次排序

一、场景说明


比如我们在CSDN中根据输入的关键词搜索博客文章,需要先根据关键词的相似度匹配排序,然后根据博客热度进行二次排序,保证热度比较高的博客文章优先被搜索到,提高用户的搜索体验。

那么,如何在ES中对检索结果进行二次排序呢?


二、误区说明


索引blog,有三个字段,博客标题title,博客内容content,博客的访问量access_num。

PUT /blog
{  
  "mappings": {
     "properties": {
      "content": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      },
      "access_num": {
        "type": "integer"
      }
    }
  }
}


检索关键词:java入门

要求:查询结果先根据匹配评分排序,再根据访问量排序。


SQL查询实现:


POST /_sql?format=txt
{
  "query": "SELECT title  FROM blog where MATCH(title, 'java入门') order by  SCORE() DESC,access_num DESC" 
}


一般情况下,我们的实现思路都是按照上面的sql进行二次排序。


问题说明:

假如现在有100万条记录能匹配上java入门关键字,先对这100万匹配的数据根据评分SCORE排序,然后再根据访问量排序,会出现如下问题

问题一:

一般全文检索时,只需要返回前面几千条记录即可,一般用户只关注匹配度最高的结果。


问题二:

通过order by SCORE() DESC,access_num DESC这样进行二次排序,那些评分较低、但是访问量较高的文章,会被排在后面,用户体验非常差。


问题三:

ES默认的match匹配打分规则,只是基于检索词的相似度词频打分,没有关联索引中的其他字段,不能实现基于title的相似度和访问量access_num组合评分。


三、优化方案


简单的一个优化思路是,先从查询结果中返回评分最高的100条记录,这100条记录再根据访问量倒序排序。

这样即可以保证评分最高的优先返回,也能保证访问量更高的被优先访问。


实现的SQL如下:


SELECT
  * 
FROM
  ( SELECT title, access_num FROM blog WHERE MATCH ( title, 'java入门' ) ORDER BY SCORE () DESC LIMIT 100 ) 
ORDER BY
  access_num DESC


存在的问题:

1、ES中不支持这种子查询,只能先查询出前100条记录,然后在程序中进行二次排序。

2、这种文章的相关度和访问量的二次排序太简单粗暴,可能文章名完全匹配的文章由于访问量比较低而不能优先被访问到,用户体验度始终不好。


补充:

通过再次评分机制rescore,可以实现对指定数据的查询结果进行二次排序。


四、终极优化


针对这种情况,更好的方式是给特定索引的全文检索查询定制打分规则,关联更多的字段信息去打分,这样就可以直接根据评分倒序排序获取前100条记录即可。


function_score 查询 是用来控制评分过程的终极武器,它允许为每个与主查询匹配的文档应用一个函数,以达到改变甚至完全替换原始查询评分 _score 的目的。

GET /blog/_search
{
    "query": {
        "function_score": {
            "query": {
                "match": {
                    "title": "java入门"
                }
            },
            "functions": [
                {
                    "script_score": {
                        "script": {
                            "params": {
                                "access_num_ratio": 2.5
                            },
                            "lang": "painless",
                            "source": "doc['access_num'].value * params.access_num_ratio "
                        }
                    }
                }
            ]
        }
    }
}

总结


本文主要是通过对ES中如何实现对查询结果的二次排序问题的思考,延展说明了ES中通过设置索引中的多个字段的权重来联合打分,从而优化用户的检索体验。

目录
相关文章
各种基础排序的超详细解析及比较
各种基础排序的超详细解析及比较
39 0
|
4月前
去重Cube的优化实践问题之直接计算去重类指标的方法具体问题如何解决
去重Cube的优化实践问题之直接计算去重类指标的方法具体问题如何解决
|
SQL Oracle 关系型数据库
SQL学习之使用order by 按照指定顺序排序或自定义顺序排序
我们通常需要根据客户需求对于查询出来的结果给客户提供自定义的排序方式,那么我们通常sql需要实现方式都有哪些,参考更多资料总结如下(不完善的和错误望大家指出): 一、如果我们只是对于在某个程序中的应用是需要按照如下的方式排序,我们只需在SQL语句级别设置排序方式:
643 0
|
存储 JSON NoSQL
MongoDB基本操作(二)——排序、分页、聚合查询、优化索引等
MongoDB基本操作(二)——排序、分页、聚合查询、优化索引等
1473 0
|
关系型数据库 MySQL
ES复杂查询-结果过滤, 排序,分页
ES复杂查询-结果过滤, 排序,分页
|
SQL 关系型数据库 MySQL
ES中如何实现类似having的先聚合再过滤查询
ES中如何实现类似having的先聚合再过滤查询
558 0
ES中如何实现类似having的先聚合再过滤查询
|
存储 SQL 关系型数据库
ES聚合查询详解(二):桶聚合
ES聚合查询详解(二):桶聚合
468 0
ES聚合查询详解(二):桶聚合
|
Java 索引
ES中如何实现随机抽样查询
ES中如何实现随机抽样查询
1301 0
ES中如何实现随机抽样查询
|
SQL 自然语言处理 关系型数据库
ES中如何实现like模糊查询
ES中如何实现like模糊查询
2234 0
ES中如何实现like模糊查询
|
Ubuntu Java 程序员
Elasticsearch聚合的嵌套桶如何排序
在elasticsearch的聚合查询中,经常对聚合的数据再次做聚合处理,这样的聚合结果如何进行排序呢,本文将对此展开讨论和实践
329 0
Elasticsearch聚合的嵌套桶如何排序