【es】elasticsearch 自定义排序-按关键字位置排序

一 背景

要求es查询的结果按关键字位置排序,位置越靠前优先级越高。

es版本7.14.0,项目是thrift,也可以平替springboot,使用easyes连接es。

二 easyes使用

配easyes按官方文档就差不多了

排序 | Easy-Es

主要的一个问题是easyes有与mybatis相同的一套mapper,如果项目也用了mybatis,那需要将mybatis、easyes的mapper分成两个目录

见:避坑指南 | Easy-Es

还有实体类的主键,按ee官方推荐是留个没注解的id自动生成id,而不是指定自己生成的主键,因为会影响数据储存的分区,导致查询效率降低

具体查询:(config、mapper、实体类略)

java 复制代码
// 查询构造
        LambdaEsQueryWrapper<EsSearchDocument> listWrapper = new LambdaEsQueryWrapper<>();
// 查询条件(相等)
        listWrapper.eq(EsSearchDocument::getType, searchType);
// 查询条件(模糊),与上条是and关系
        listWrapper.like(EsSearchDocument::getTitle, searchContent);
// 分页偏移量计算
        int offset = ((pageNum != null ? Integer.parseInt(pageNum) : 1) - 1) * size;
//查询总条数
        Long count = esMapper.selectCount(listWrapper);
// 设置分页
        listWrapper.limit(offset, size); // 分页
// 查询结果列表
        List<EsSearchDocument> esList = esMapper.selectList(listWrapper);
        
//打印
        System.out.println("count="+count);
        System.out.println(JSON.toJSONString(esList));

三 自定义排序

es官方排序是按重复次数、内容长度、权重之类,用一个啥公式算出来分数排的

大学也许还能看懂点,现在是完全不懂了

easyes也提供了按字段排序之类(见上面官方文档链接)

回到问题,es、ee都没有按关键字位置排序的。不过es、ee还提供了自定义脚本 painless,可以自己写处理方式。那就好说了,在脚本里获得字段原文,indexof拿到关键字所在位置,根据这个值排序。

大部分网上的文档这么写(包括文心一言):

可以看到取原文的写法是 doc'字段.keyword'.value

经过实测会报错:

1 字段.keyword 不存在。去掉.keyword能取到,但取得是内容片段,比如原文"金坷垃好处都有啥",这个word/words值是"都有啥"。

2 text类型字段不能拆出来排序,否则报错:

Text fields are not optimised for operations that require per-document field data like aggregations

意思就是text类型字段被es禁用了聚合、排序操作,要么加注解(fielddata=true)才能解锁,要么改成keyword类型。但加注解会影响效率,有多影响待观察。

这个字段是用了ik分词器的,去掉分词器后(谨慎改变实体类,每次改变都会试es数据清空),word值成了"啥"

到这里已经一整天过去了

然后翻阅es的官方文档,终于发现这么一句:

Field context | Painless Scripting Language 7.14 | Elastic

意思是 doc'字段'写法不适用于text类型字段。想取到原值可以 params'_source''字段'

试了下还真可以。

param是可以传动态参数的,使脚本避免反复编译提高效率。另外doc、_source、ctx是结合上下文在不同场景用的,比如doc是_search查询用的,但这个问题的查询就用了_source,不能太死板

探究 | Elasticsearch Painless 脚本 ctx、doc、_source 的区别是什么?-腾讯云开发者社区-腾讯云

最后加了这么一段

java 复制代码
// 定义脚本
        String painlessScriptStr = " String word = params['_source']['title'];" + 
                " int position = (word != null && !''.equals(word)) ? word.indexOf(params['searchContent']) : -1; " + 
                " return position; ";
        // 自定义评分规则
        
        Script script = new Script(ScriptType.INLINE, "painless", painlessScriptStr, Collections.singletonMap("searchContent", searchContent));
        ScriptSortBuilder ssb = new ScriptSortBuilder(script, ScriptSortBuilder.ScriptSortType.NUMBER)
                .order(SortOrder.ASC);

        listWrapper.sort(ssb);
相关推荐
风流 少年19 小时前
Spring AI 2.0:阿里云百炼平台(工作流应用)
java·后端·spring
长谷深风11119 小时前
AI Tool 设计:粒度、参数与错误恢复怎么做
java·大数据·人工智能·ai agent·agent工作流·智能体设计·ai产品设计
QQ_216962909620 小时前
【项目编号:project95315】SpringBoot公共自习室管理系统:座位预约、房间管理、签到核销、公告规则完整实战
java·spring boot·后端
嵌入式阿蔡21 小时前
面试高频考点 01:volatile / 中断 / 堆栈 八股精讲
java·面试·职场和发展·嵌入式实时数据库
秋饼21 小时前
LangChain4j + Java 实现企业级 Text-to-SQL 智能问数系统:从自然语言到安全可控的数据洞察
java·ai·技术分享·后端开发
Escalating_xu21 小时前
【C++ STL简介】从六大组件到容器、迭代器与算法协作
java·c++·算法
何以解忧,唯有..21 小时前
Python os模块详解:文件与目录操作指南
java·服务器·python
Csxyzj21 小时前
kubernetes集群部署方法
java·linux·kubernetes
SQL-First布道者1 天前
全面解构传统持久层框架,拥抱真正的 SQL-First
java·数据库·spring boot·sql·spring·mybatis·spring jdbc
leoZ2311 天前
10-Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人-蒸馏工具链
大数据·git·深度学习·神经网络·目标检测·elasticsearch·lstm