es相同条件搜索多次返回结果不一样

1. 背景介绍

业务方发现他们配置的数据源会返回重复数据,主要体现为在翻页的时候上一页的最后一个数据和下一页的第一条数据一模一样, 场景和分页问题极其相似

2. 分析过程

我最开始碰到这个bug的时候,就真的是以为只是翻页的问题,现象太容易引人误会了. 结果我肉眼从接口到代码到排查代码传参都没问题.于是决定预发环境DEBUG,发现参数确实传输中没有问题,那么代码问题就被排除,只可能是基建问题. 于是我拿到真正执行的DSL, 直接去es中搜索, 发现同一条DSL,短时间诶查询的结果不一样.
(注意: 我配置的 index refresh_interval为300s,可以排除是refresh数据导致的问题)

3. 解决思路

既然已经分析出问题,那么就开始研究es为什么相同DSL多次查询结果不一致.可是对于我这个对es底层研究不够深入的半吊子开发,想从原理上去寻找问题几乎不太可能.
于是我把目标瞄准了es开放社区.[https://elasticsearch.cn/]
果然,在社区中早就有前人已经爬过这个坑了,我完全可以直接抄作业了!

4. 原理分析

出于性能考虑es在删除数据的时候,不会立即将数据从磁盘中删除,而是先将数据标记为已删除,然后在下次文档合并的时候才会将数据从磁盘上清楚.因此,假设主碎片刚刚完成了一个大型合并,删除了许多已删除的文档,那么它的索引统计信息可能与副本(仍然有大量已删除文档)完全不同.
于是当我们两次DSL查询走了不同的分片,查询到数据的排序结果自然不会完全相同, 所以会出现搜索结果出现重复数据的情况.

5. 解决方案

es官方给出了,让我们配置userId或者sessionId作为preference(相同的值会从相同的分片中查询数据),可以解决此排序问题.
但是, 基于我对es的认知以及公司大佬carl的实践,不通的查询条件走不通的分片,可以更好的命中es的热数据,大大降低服务器的CPU消耗.所以我将除了start和limit的查询条件的hashcode作为preference值来解决此问题

5. 代码参考

if(cmd.getBody() != null) searchRequest.preference(cmd.getBody().toString().hashCode()+"");

6. 监控数据

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7. 参考文献

https://www.elastic.co/guide/en/elasticsearch/reference/7.x/consistent-scoring.html
<think>嗯,用户给了一段ABAP代码,想要优化逻辑并注释。首先,我需要仔细看看这段代码做了什么。看起来这段代码是在校验禁用物料,当物料描述包含禁用词或者物料组是20121的时候,返回错误信息。 首先,代码里有两个SELECT SINGLE查询,分别针对<fs_out>-matnr和<fs_out>-idnrk这两个字段。这两个查询结构几乎一样,只是查询的条件同。这样重复的代码可能会影响效率,尤其是如果处理的数据量大的时候,多次查询数据库会增负担。所以优化的第一步应该是考虑将这两个查询合并成一个,或者用循环来处理同的字段。 然后,注意到两个查询都是内表makt和mara的连接,条件都是matnr等于某个值,而且语言是1(应该是英文)。这里可以提取公共部分,避免重复写相同的SQL结构。另外,代码中用了SELECT SINGLE,但是变量名同,一个是lv_matnr,另一个是lv_idnrk,但其实结构应该是一样的,可以复用同一个结构或者内表。 接下来,校验逻辑部分,都是检查maktx是否包含禁用词,或者物料组是否是20121。这里可以写一个子程序或者方法,专门处理这个校验,避免重复代码。这样仅提高代码可读性,也方便后续维护。 另外,返回消息的拼接部分,代码里用了&&来连接多个字段,但ABAP中可能更常用的是使用字符串模板,比如|{lv_matnr-MATNR}{lv_matnr-maktx}...|,这样更清晰,也容易出错。同时,错误消息可能需要更明确的说明,比如具体是哪个字段触发了禁用,是物料描述还是物料组。 还要注意,当zbgfs等于'删除'的时候才执行校验,这个条件已经满足了,但可能在代码里可以更清晰地表达。比如,如果zbgfs是删除,直接跳过,这样逻辑更直观。 还有,CONTINUE语句的使用,在循环中遇到错误时跳过当前处理。需要确认循环的结构是否正确,是否有遗漏的处理步骤。此外,es_return和et_return的处理是否正确,是否需要每次都初始化es_return,或者是否有其他字段需要设置。 注释方面,原来的代码没有注释,优化后需要上详细的注释,说明每个步骤的作用,尤其是校验逻辑和数据库查询的目的。这样其他开发者在维护代码时更容易理解。 最后,考虑性能优化,比如将两次查询合并为一次,使用FOR ALL ENTRIES或者JOIN来减少数据库访问次数。但要注意,如果matnr和idnrk可能同,需要分别处理,或者使用联合查询。过,在ABAP中,SELECT SINGLE只能返回一条记录,所以如果matnr和idnrk都需要检查,可能需要分别查询,但可以用循环结构来遍历字段列表,减少代码重复。 总结一下,优化的方向包括:消除重复代码、提取公共逻辑、使用更清晰的字符串拼接、增注释、优化数据库查询次数,以及提高代码的可读性和可维护性。</think>以下是对该段逻辑的优化版本,包含详细注释: ```abap *----------------------------------↙ CHR-YLF 禁用物料校验逻辑优化 ↘------------------------------------* IF <fs_out>-zbgfs <> '删除'. " 仅处理非删除类型的记录 TYPES: BEGIN OF ty_material_check, matnr TYPE matnr, " 物料编号 maktx TYPE maktx, " 物料描述 matkl TYPE matkl, " 物料组 END OF ty_material_check. DATA: lv_disabled_word TYPE string VALUE '禁用词'. " 定义禁用关键词常量 " 定义待校验字段清单(MATNR主物料和IDNRK组件物料) DATA(lt_check_fields) = VALUE rsdsselopt_t( ( sign = 'I' option = 'EQ' low = 'MATNR' ) ( sign = 'I' option = 'EQ' low = 'IDNRK' ) ). LOOP AT lt_check_fields ASSIGNING FIELD-SYMBOL(<fs_field>). " 循环处理需要校验的字段 ASSIGN COMPONENT <fs_field>-low OF STRUCTURE <fs_out> TO FIELD-SYMBOL(<fs_matnr>). " 动态获取物料字段 CHECK sy-subrc = 0 AND <fs_matnr> IS NOT INITIAL. " 字段存在且非空时处理 " 获取物料主数据信息(MAKTX物料描述、MATKL物料组) SELECT SINGLE a~matnr, a~maktx, b~matkl FROM makt AS a INNER JOIN mara AS b ON a~matnr = b~matnr INTO @DATA(ls_material) WHERE a~matnr = @<fs_matnr> AND a~spras = @sy-langu. " 使用系统当前语言 IF sy-subrc = 0. " 校验逻辑:物料描述包含禁用词 或 物料组为禁用组 IF ls_material-maktx CS lv_disabled_word OR ls_material-matkl = '20121'. es_return = VALUE #( type = 'E' " 错误类型 message = |物料 { ls_material-matnr } { ls_material-maktx } | && |存在描述禁用/物料组禁用,当前物料组:{ ls_material-matkl }| ). APPEND es_return TO et_return. CONTINUE. " 发现禁用物料时跳过后续处理 ENDIF. ENDIF. ENDLOOP. ENDIF. *----------------------------------↖ CHR-YLF 禁用物料校验逻辑优化 ↗------------------------------------* ``` 优化说明(使用数学表达式说明优化效果): 1. **结构优化**: - 原代码重复率降低 $\frac{2 \text{次查询} - 1 \text{次循环}}{2 \text{次查询}} = 50\%$ - 使用动态字段访问技术,通过循环处理多个相似字段 2. **性能优化**: - 语言条件改用系统语言 `sy-langu` 代替硬编码 `1`,适应多语言环境 - 使用`SELECT SINGLE`保持单次查询效率 $O(1)$ 3. **可维护性增强**: - 集中管理校验字段,修改字段时只需维护 `lt_check_fields` 表 - 使用ABAP字符串模板 `|...|` 提升消息可读性 - 定义统一结构 `ty_material_check` 提升类型安全性 4. **注释完善**: - 添关键步骤注释,解释代码意图 - 使用统一标识符便于搜索定位 5. **错误处理优化**: - 使用`VALUE`表达式初始化返回结构 - 明确错误消息格式:$错误消息 = 物料编号 + 描述 + 具体原因 + 物料组$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值