如何在ElasticSearch/OpenSearch中排除含点的handler_id?
1. 先揪出当前正则的核心问题
(1)must_not的逻辑完全搞反了
原must_not里的正则[^_*\-.;?#$%^@!,/?+()~<>:'\[\]{}],[^...]是匹配**不在集合里的字符**,加后意思是“匹配0次或多次非特殊字符”——这相当于只要字段里没有特殊字符就会被排除,完全和你要的“排除含特殊字符的项”逻辑相反。而且末尾多了个,语法都有问题,等于这个must_not条件根本没生效。
(2)must的正则没做全字段匹配
OpenSearch的regexp默认是部分匹配,只要字段里有一段符合就会命中,原正则~([^.])*[A-Za-z]{2}[a-zA-Z0-9]{2}[0-9]{8}里的~是普通字符,.MP4137879580里的MP4137879580部分刚好符合后面的格式段,所以就算开头有.也会被匹配到。
2. 一步步修正验证
修正must_not:精准排除含特殊字符的项
直接写匹配“任意位置包含特殊字符”的正则,用.*包裹特殊字符集,这样只要字段里有任何一个特殊字符,就会被must_not排除:"must_not": [ { "regexp": { "handler_id.keyword": ".*[_*\\-.;?#$%^@!`,/?+()~<>:'\\[\\]{}].*" } } ]给must的正则加锚点,强制全字段匹配
要确保整个handler_id符合格式,必须加^(字段开头)和$(字段结尾),同时用handler_id.keyword匹配原始完整值(避免分词干扰):"must": [ { "regexp": { "handler_id.keyword": "^[A-Za-z]{2}[a-zA-Z0-9]{2}[0-9]{8}$" } } ]这样
.MP4137879580开头的.就会因为不满足开头的字母要求被排除。单独测试每个条件
用_validate/query工具单独验证正则是否生效,比如:GET _validate/query?q=handler_id.keyword:^[A-Za-z]{2}[a-zA-Z0-9]{2}[0-9]{8}$&explain=true或者单独跑must或must_not的查询,看是否能正确过滤目标值。
检查字段类型
如果handler_id是text类型,分词会导致正则匹配的是拆分后的片段,必须用handler_id.keyword来匹配原始的完整字符串。
3. 修正后的完整查询
GET _search { "from": 0, "size": 10, "query": { "bool": { "must_not": [ { "regexp": { "handler_id.keyword": ".*[_*\\-.;?#$%^@!`,/?+()~<>:'\\[\\]{}].*" } } ], "must": [ { "regexp": { "handler_id.keyword": "^[A-Za-z]{2}[a-zA-Z0-9]{2}[0-9]{8}$" } } ] } }, "sort": [ { "handler_id.keyword": { "order": "asc" } } ] }
内容的提问来源于stack exchange,提问作者Leo

