草庐IT

es的must_not的踩坑

幸平xp 2023-07-25 原文

文章目录


前言

记录下在公司做需求时must_not踩的坑


一、需求背景

要去做人才库的一个排除项:排除x个月面试不通过。实际上的dsl语句则对应的是must_not。且内部要包含两个元素:x个月、面试不通过(C、D)取交集。

二、坑

2.1 坑一

目标测试数据为:

这是一条面试时间为10.21、且面评不合格的一条数据。
一开始拼接的dsl语句为(to默认为当前时间戳):

  • 在must_not中同时拼接两个条件:1毫秒前面试不通过的,按理来说应该出现目标数据。可是确没有命中。
  • 接下来开始排查,将下面关于面试不通过的去掉:

    发现可以hit:

    再换成将上面的时间去掉,发现找不到,符合预期结果。
    那么可以猜想:内层单个的should都生效了,问题点出现在了外层的must_not联合的作用上。
    直观点表示就是预期本来是这样的:

    可是实际上却变成了这样:


以至于这条数据在内层因为面试不通过就被筛出来了,而无关面试结束在x个月。最后再来一个must_not导致无法hit。

  • 那么为了验证我们的猜想可以做这样的操作:

    也就是在之间再通过must将两者关联起来,再来一个must_not。对应的dsl语句为:

    这时候再来试一次:

    发现可以命中的到,而改大时间范围:

    发现已经搜索不到了。这时就可以得出结论。
  • 对于must_not中有多个must或者should(如果是should得保证同级没must具体见官方文档),他其实是must_not:must + must_not:must。而不是内层先进行包含,最后再进行must_not。如果要实现内层包含。则应该内层嵌套一个must进行联合。

2.2 坑二

  • 还是对于同一个需求,虽然改好了上面的漏洞。但是其实还是有一个问题:上面的数据其实为在nested列表对象下长度为1的一条数据。那么试想一下换另外一条数据呢?

例如:

那么这条数据如果在面试在超过这个时间不通过的情况下对于上面的数据理应不该被搜出来。
可是如果是用刚刚拼接好的完整dsl:

"nested": {
                "query": {
                  "bool": {
                    “must_not": [
                      {
                        "bool": {
                          "must": [
                            {
                              "bool": {
                                "should": [
                                  {
                                    "range": {
                                      "interviewInfos.interviewEndTime": {
                                        "from": "1651388570",
                                        "to": "1667185560684",
                                        "include_lower": true,
                                        "include_upper": true,
                                        "boost": 1
                                      }
                                    }
                                  }
                                ],
                                "adjust_pure_negative": true,
                                "boost": 1
                              }
                            },
                            {
                              "bool": {
                                "should": [
                                  {
                                    "terms": {
                                      "interviewInfos.interviewScore": [
                                        "U004",
                                        "U005"
                                      ],
                                      "boost": 1
                                    }
                                  }
                                ],
                                "adjust_pure_negative": true,
                                "boost": 1
                              }
                            }
                          ]
                        }
                      }
                    ],
                    "adjust_pure_negative": true,
                    "boost": 1
                  }
                },
                "path": "interviewInfos",
                "ignore_unmapped": false,
                "score_mode": "max",
                "boost": 0
              }"nested": {
                "query": {
                  "bool": {
                    “must_not": [
                      {
                        "bool": {
                          "must": [
                            {
                              "bool": {
                                "should": [
                                  {
                                    "range": {
                                      "interviewInfos.interviewEndTime": {
                                        "from": "1651388570",
                                        "to": "1667185560684",
                                        "include_lower": true,
                                        "include_upper": true,
                                        "boost": 1
                                      }
                                    }
                                  }
                                ],
                                "adjust_pure_negative": true,
                                "boost": 1
                              }
                            },
                            {
                              "bool": {
                                "should": [
                                  {
                                    "terms": {
                                      "interviewInfos.interviewScore": [
                                        "U004",
                                        "U005"
                                      ],
                                      "boost": 1
                                    }
                                  }
                                ],
                                "adjust_pure_negative": true,
                                "boost": 1
                              }
                            }
                          ]
                        }
                      }
                    ],
                    "adjust_pure_negative": true,
                    "boost": 1
                  }
                },
                "path": "interviewInfos",
                "ignore_unmapped": false,
                "score_mode": "max",
                "boost": 0
              }

但是结果是会hit,而不会被排除。
那么接下来继续排查,排查的一个关键点在于我直接把最外层的must_not直接改成must。

发现直接取反后的结果竟然也是被hit到了,也就是最外层的must/must_not的结果失效了。
那么比对一下两者数据的差别:在于nested的数据长度上。
那么可以得到一个猜想:关于nested内的must,must_not,最终只是hit其中一段元数据。也就是虽然这个数据被排除了,但是这个nested列表中的第二条、第三条… hit了,那么这个候选人依旧可以选出来。也就是说红框这部分被搜索出来了:

如果想要排除这个人,那么可以猜想需要直接把must_not放在nested外面。也就是:

"must_not": [
            { "nested": {
                "query": {
                  "bool": {
                    "must": [
                      {
                        "bool": {
                          "must": [
                            {
                              "bool": {
                                "should": [
                                  {
                                    "range": {
                                      "interviewInfos.interviewEndTime": {
                                        "from": "1667203393540",
                                        "to": "1667203393541",
                                        "include_lower": true,
                                        "include_upper": true,
                                        "boost": 1
                                      }
                                    }
                                  }
                                ],
                                "adjust_pure_negative": true,
                                "boost": 1
                              }
                            },
                            
                            {
                              "bool": {
                                "should": [
                                  {
                                    "terms": {
                                      "interviewInfos.interviewScore": [
                                        "U004",
                                        "U005"
                                      ],
                                      "boost": 1
                                    }
                                  }
                                ],
                                "adjust_pure_negative": true,
                                "boost": 1
                              }
                            }
                          ]
                        }
                      }
                    ],
                    "adjust_pure_negative": true,
                    "boost": 1
                  }
                },
                "path": "interviewInfos",
                "ignore_unmapped": false,
                "score_mode": "max",
                "boost": 0
              }}
          ],

修改发现符合最终需要的结果。

总结

踩了这几个坑,虽然写出来排查的过程很简单,但实际还是挺头疼的,需要不断的进行变量对比。不断的去写dsl语句,最终在文中只是关键的排查点。得到的经验也很简单,要从最里层一层一层的扒。每个must,must_not就像一层层列表便利,只不过每次遍历就是must,must_not中的元素。

有关es的must_not的踩坑的更多相关文章

  1. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  2. ES基础入门 - 2

    ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear

  3. ruby-on-rails - bundler : not executable: script/delayed_job - 2

    我正在尝试在我的远程服务器上运行以下命令(通过capistrano或ssh):bundleexecRAILS_ENV=productionscript/delayed_jobstart但我收到此错误消息:bundler:notexecutable:script/delayed_job以前从未见过这个,谷歌也没有适合我的东西。知道可能是什么问题吗? 最佳答案 也许它没有运行权限?尝试运行这个命令chmod+xscript/delayed_job然后再次执行文件。 关于ruby-on-rai

  4. ruby-on-rails - Rails FasterCSV "unquoted fields do not allow\r or\n" - 2

    我在使用FasterCSV和我的rakedb:seeds迁移时遇到问题。我收到错误:“rake中止!未加引号的字段不允许\r或\n(第2行)”在以下seeds.rb数据上:require'csv'directory="db/init_data/"file_name="gardenzing020812.csv"path_to_file=directory+file_nameputs'LoadingPlantrecords'#Pre-loadallPlantrecordsn=0CSV.foreach(path_to_file)do|row|Plant.create!:name=>row[1

  5. ruby-on-rails - Rails 5,公寓和设计 : sign in with subdomains are not working - 2

    我已经使用Apartment设置了一个Rails5应用程序(1.2.0)和Devise(4.2.0)。由于某些DDNS问题,应用只能在app.myapp.com下访问(请注意子域app)。myapp.com重定向到app.myapp.com。我的用例是每个注册该应用的用户(租户)都应该通过他们的子域(例如tenant.myapp.com)访问他们的特定数据。用户不应限定在其子域内。基本上应该可以从任何子域登录。重定向到租户的正确子域由ApplicationController处理。根据Devise标准,登录页面位于app.myapp.com/users/sign_in。这就是问题开始的

  6. ruby-on-rails - 安装 active admin 时 activeadmin.git (at master) is not yet checked out 错误 - 2

    Activeadmingem已添加到我的rails项目中,但每次我尝试安装railsgactive_admin:install时,我都会收到类似的错误git://github.com/activeadmin/activeadmin.git(atmaster)isnotyetcheckedout.Runbundleinstallfirst.我肯定在运行“railsgactive_admin:install”之前运行了bundle。运行“bundleshow”后,我看到我已将“*activeadmin(1.0.0.pre3f916d6)”添加到我的项目中,但不断收到此错误消息。我的gem文

  7. ruby-on-rails - Assets 管道损坏 : Not compiling on the fly css and js files - 2

    我开始了一个新的Rails3.2.5项目,Assets管道不再工作了。CSS和Javascript文件不再编译。这是尝试生成Assets时日志的输出:StartedGET"/assets/application.css?body=1"for127.0.0.1at2012-06-1623:59:11-0700Servedasset/application.css-200OK(0ms)[2012-06-1623:59:11]ERRORNoMethodError:undefinedmethod`each'fornil:NilClass/Users/greg/.rbenv/versions/1

  8. css - rails 萨斯 : variables are not passed with @import - 2

    我有一个使用twitterbootstrap和sass的Rails元素。scss文件结构化到文件夹中,所以我有更好的概述。现在我想为包含我的颜色等的全局变量定义一个文件,并将这些值传递给其他文件,这样我就有更少的冗余代码。虽然所有代码都已正确导入和应用,变量不起作用。这是当前的设置:样式表/application.css.scss/**=require_self*=require_tree*//*stylesheets/||–base/||–_reset.scss#Reset/normalize||–_typography.scss#Typographyrules||–componen

  9. ruby - Nokogiri 'not' 选择器 - 2

    Nokogiri中是否有一种方法可以选择所有与选择器不匹配的元素。在jQuery中我会使用::not(*[@class='someclass'])但是下面的代码给我一个xpath语法错误dom=Nokogiri::HTML(@file)dom.css(":not(*[@class='someclass'])") 最佳答案 InCSS3,:not()takesaselectorlikeanyother,所以它会是:dom.css(":not(.someclass)")(未经测试,但选择器是正确的)

  10. ruby-on-rails - OSX 10.7.5 - Ruby on Rails LoadError : Could not open library 'sodium' : dlopen(sodium, 5) - 2

    输入rakedb:create后我得到:LoadError:Couldnotopenlibrary'sodium':dlopen(sodium,5):imagenotfound.Couldnotopenlibrary'libsodium.dylib':dlopen(libsodium.dylib,5):imagenotfound这里还有一些输出。/Users/Mao/.rvm/gems/ruby-2.0.0-p451/gems/ffi-1.9.3/lib/ffi/library.rb:133:in`blockinffi_lib'/Users/Mao/.rvm/gems/ruby-2.0

随机推荐