Elasticsearch : 使用 Pinned query 实现置顶需求

303 阅读4分钟

文档索引

ES 7.4 版本 Pinned Query 新特性介绍
ES 8.11 当前版本 Pinned Query 文档
ES 掘金作者 Pinned Query 介绍

特性简介

Pinned query 特性在 ES7.4 版本中被引入, 其主要作用是将特定id的文档固定在搜索结果的最前端。

示例请求:

GET /_search
{
  "query": {
    "pinned": {
      "ids": [ "1", "4", "100" ],
      "organic": {
        "match": {
          "description": "iphone"
        }
      }
    }
  }
}

参数:

  • ids 需要固定在最前方的文档对应的_id,英文文档中有一些微妙的描述 ,后面再统一解释。

(Optional, array) Document IDs listed in the order they are to appear in results. Required if docs is not specified.

  • docs (可选,数组)按文档在结果中的显示顺序列出的文档。如果未指定ID,则为必需项。该选项最早在7.15版本的文档中出现,早期的ES版本没有加入该选项(测试版本7.4.2)参数包含:_index_id,可以用于跨多个索引的检索。官方示例如下:
GET /_search
{
  "query": {
    "pinned": {
      "docs": [
        {
          "_index": "my-index-000001",
          "_id": "1"
        },
        {
          "_index": "my-index-000001",
          "_id": "4"
        },
        {
          "_index": "my-index-000002",
          "_id": "100"
        }
      ],
      "organic": {
        "match": {
          "description": "iphone"
        }
      }
    }
  }
}
  • organic 用于对排名在“固定”文档之下的文档进行排名的任何查询选项。英文翻译非常拗口,可以理解为除固定文档外需要执行的查询。

使用测试

下面是一些关于Pinned Query 查询的使用测试情况,版本基于 ES 7.4.2
创建文档如下:

PUT /test-index
{
  "mappings": {
    "properties": {
      "num": {
        "type": "integer"
      }
    }
  }
}

PUT /test-index/_doc/1
{
  "num":1
}

PUT /test-index/_doc/2
{
  "num":2
}

PUT /test-index/_doc/3
{
  "num":3
}

PUT /test-index/_doc/4
{
  "num":4
}

测试1:ids参数

先说测试结果:

  1. 测试是否必须:是,参数一定要存在。(高版本和 docs参数 选其一)
  2. 测试是否可为空:否,参数不能为空。
  3. 测试是否可传单个参数:是,参数可以以单个形式传递。
  4. 测试是否可传空数组:是,空数组不会产生报错。
  5. 测试ids文档号不在索引中的情况:不会报错,不会影响排序。
  6. 测试ids文档固定的文档数上限:100,超过100将报错。
// 测试是否必须
GET /test-index/_search
{
    "query": {
        "pinned" : {
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
            }
        }
    }
}

// 测试是否可为空
GET /test-index/_search
{
    "query": {
        "pinned" : {
          "ids" : "",
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
            }
        }
    }
}

// 测试是否可传单个参数
GET /test-index/_search
{
    "query": {
        "pinned" : {
          "ids" : "1",
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
            }
        }
    }
}

// 测试是否可为空数组
GET /test-index/_search
{
    "query": {
        "pinned" : {
          "ids" : [],
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
            }
        }
    }
}

// 测试 ids 文档号不在索引中的情况
GET /test-index/_search
{
    "query": {
        "pinned" : {
            "ids":[5],
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
              
            }
        }
    }
}

// 测试 ids 固定文档上限
GET /test-index/_search
{
    "query": {
        "pinned" : {
            "ids":["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71","72","73","74","75","76","77","78","79","80","81","82","83","84","85","86","87","88","89","90","91","92","93","94","95","96","97","98","99","100","101"],
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
              
            }
        }
    }
}

测试2:organic 参数

测试结果:

  1. 测试是否必须:是,不传organic参数会直接报错,也不能空对象。
  2. 测试bool查询:可以正常编写复杂查询。
// 是否必须
GET /test-index/_search
{
    "query": {
        "pinned" : {
          "ids" : "1"
        }
    }
}

// bool 查询
GET /test-index/_search
{
    "query": {
        "pinned" : {
          "ids" : "1",
            "organic" : {
              "bool" : {
                "must" :{
                  "range" : {
                    "num" : {
                      "gte" : 0
                    }
                  }
                }
              }
            }
        }
    }
}

测试3:排序

测试结果:

  1. 测试多个ids参数排序:多个参数排序取决于传入的顺序。
  2. 测试添加sort排序:外层sort的排序会影响pinned query,排序将重排,排序结果将取决于sort的结果,固定效果将失效。
// 多个 ids 参数排序
GET /test-index/_search
{
    "query": {
        "pinned" : {
            "ids":[2,3],
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }  
            }
        }
    }
}

// 添加 sort 排序
GET /test-index/_search
{
  "sort": [
    {
      "num": {
        "order": "desc"
      }
    }
  ], 
    "query": {
        "pinned" : {
            "ids":[2,3],
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
            }
        }
    }
}

注:由于sort排序将影响 pinned querypinned query会提高固定文档的得分,可以考虑将_score纳入sort排序中进行调整。
参考:

GET /test-index/_search
{
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    },
    {
      "num": {
        "order": "desc"
      }
    }
  ], 
    "query": {
        "pinned" : {
            "ids":[2,3],
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
            }
        }
    }
}

// 运行结果
// 2,3 文档将固定在前面,其他文档将按num大小排序

测试4: 分页

测试结果:

  1. 测试分页首页数量受pinned query影响: 不受影响,size 指定多少就是多少。
  2. 测试下一页是否会出现固定文档:不会出现固定文档,固定文档只会出现在首页,正确来说是按得分顺序排序下来。
// 测试数量
GET /test-index/_search
{
    "size":2,
    "from":0,
    "query": {
        "pinned" : {
            "ids":[1],
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
              
            }
        }
    }
}

// 测试下一页是否会出现固定文档
GET /test-index/_search
{
    "size":2,
    "from":2,
    "query": {
        "pinned" : {
            "ids":[1],
            "organic" : {
                "range" : {
                  "num" : {
                    "gte" : 0
                  }
                }
              
            }
        }
    }
}

如有错漏,欢迎评论指正。