1、实战问题
如何根据输入的id 的顺序输出结果,id 个数有500个,还有分页?
问题来源:https://t.zsxq.com/0cdyq7tzr
2、方案探讨
2.1 Elasticsearch 默认排序机制
- 在 Elasticsearch 中,如果未指定排序规则,检索结果的默认排序方式是按照文档的相关性得分(_score)进行降序排序。相关性得分表示了文档与查询的匹配程度。得分越高,文档与查询的匹配程度越高。
- 有些情况下,查询结果的评分可能不相关或无法计算。例如,在过滤查询(如 term、terms 或 ids 查询)或布尔查询的 filter、must_not上下文中,Elasticsearch 不会计算评分。在这些情况下,文档的评分通常为 1.0 或其他默认值(filter、must_not 评分为0)。
2.2 如何基于用于指定的 ID 顺序召回数据?
原生的 Elasticsearch 检索机制没有这个功能。那就意味着,咱们得自己实现。
如何实现呢?把用户给定的序列(非递增也非递减的无规律序列,如3、1、5、7),看成一维数组数据。
他们的数组的下标只能是0、1、2、3.....也就是说,下标是有序的。
那么接下来问题就转嫁为如何基于数组下标进行升序排序的问题?
借助 sort 排序的 script 脚步排序即可实现。
3、前置条件
PUT /_cluster/settings { "transient": { "indices.id_field_data.enabled": true } }
解读如下:
PUT /_cluster/settings 请求是 Elasticsearch 中用于更新集群设置的 API。这个特定请求的含义是,我们要更新集群的临时(transient)设置。
{"transient": {"indices.id_field_data.enabled": true}}
在这个请求中,我们设置了 indices.id_field_data.enabled 为 true。
这个设置用于控制 Elasticsearch 是否允许对 _id 字段进行 fielddata 访问。
默认情况下,这个设置是禁用的(false),因为访问 _id 字段的 fielddata 可能会消耗大量内存,并可能导致性能下降。
这里使用的 transient 属性意味着设置的更改是临时的,只在集群重启之前有效。当集群重新启动时,这个设置会被重置为默认值。如果您希望永久更改此设置,可以使用 persistent 属性:
PUT /_cluster/settings {"persistent": {"indices.id_field_data.enabled": true}}
请注意,在实际应用中,我们通常不建议启用 _id 字段的 fielddata 访问,因为它可能会导致性能问题。
4、给出样例数据
给出批量数据,以备后用!
PUT test_index/_bulk {"index":{"_id":1}} {"title":"001"} {"index":{"_id":3}} {"title":"003"} {"index":{"_id":5}} {"title":"005"} {"index":{"_id":7}} {"title":"007"}
5、给出实现
POST test_index/_search { "query": { "ids": { "values": [ "3", "1", "5", "7" ] } }, "sort": [ { "_script": { "type": "number", "script": { "lang": "painless", "source": """ List ids_list = params.ids; String cur_id = doc['_id'].value; for(int i = 0; i < ids_list.length; i++) { if(cur_id.equals(ids_list[i])) { return i; } } return -1; """, "params": { "ids": ["3","1","5","7"] } }, "order": "asc" } } ] }
实现解读:
这个 Elasticsearch 查询用于从名为 test_index 的索引中搜索文档。查询的主要目的是根据给定的 ID 列表检索文档,并按照 ID 列表的顺序对检索到的文档进行排序。
以下是查询的各个部分的详细解释:
- size: 设置为 10,表示查询将返回最多 10 个文档。在这种情况下,由于我们的 ID 列表只包含 4 个 ID,因此查询将返回最多 4 个文档。
- query: 使用 ids 查询来筛选给定 ID 列表中的文档。在这个例子中,我们要检索 ID 为 "3"、"1"、"5" 和 "7" 的文档。
- sort: 使用脚本排序(_script)按照给定的 ID 列表的顺序对返回的文档进行排序。-- type: 设置为 "number",表示脚本返回的值将被视为数字。
- script: 定义了一个 Painless 脚本,用于计算每个文档的排序值。
- lang: 设置为 "painless",表示脚本使用 Painless 语言编写。
- source: 脚本的源代码。这个脚本遍历给定的 ID 列表,查找与当前文档 _id 匹配的 ID。如果找到匹配项,则返回匹配项在 ID 列表中的索引作为排序值。如果没有找到匹配项,返回 -1(在这个例子中,实际上不会发生)。
- params: 脚本的参数,包含一个名为 ids 的列表,其中包含了要排序的 ID。这里,我们将 ID 列表作为参数传递给脚本。
- order: 设置为 "asc",表示按升序对文档进行排序。这意味着查询结果将按照 ID 列表的顺序返回。
通过这个查询,您可以从 test_index 索引中获取指定 ID 的文档,并按照给定的 ID 顺序("3"、"1"、"5"、"7")对结果进行排序。
6、小结
关于分页,参考普通检索实现即可。
本文结合脚本排序的方式实现了基于用户指定顺序召回结果数据。视频解读如下:
大家有没有更好的实现方式呢?欢迎留言交流。
推荐阅读
更短时间更快习得更多干货!
和全球 近1900+ Elastic 爱好者一起精进!
比同事抢先一步学习进阶干货!