ElasticSearch:筛选含允许字符且支持指定数量通配符的结果
在Elasticsearch中实现带通配符限制的字符过滤需求
需求说明
- 基于指定允许字符列表过滤文档,保留仅包含允许字符的记录,同时支持最多X个通配符(即允许X个不在列表中的字符)
- 允许列表中的字符可无限制重复使用(例如
a可匹配aaaaaa) - 通配符支持两种场景:限制非允许字符的出现数量(如最多2个)、以及匹配任意长度的非允许内容(如
*通配符)
示例(允许字符:[a,b,c],通配符数量0-2)
| 数据集 | 无通配符 | 1个通配符 | 2个通配符 | |||
|---|---|---|---|---|---|---|
| id | value | id | value | id | value | id |
| 1 | aabc | 1 | aabc | 1 | aabc | 1 |
| 2 | aabcd | 4 | cba | 2 | aabcd | 2 |
| 3 | axbd | 4 | cba | 3 | ||
| 4 | cba | 4 |
实现方案
1. 无通配符场景(仅保留允许字符组成的记录)
使用regexp查询,确保字段所有字符都属于允许列表:
{ "query": { "regexp": { "value": "^[abc]+$" } } }
解释:^和$锁定字段首尾,[abc]+匹配一个或多个a/b/c字符。
2. 最多N个非允许字符(通配符数量限制为N)
通过Painless脚本统计字段中不属于允许列表的字符数量,筛选数量≤N的文档:
最多1个非允许字符的查询:
{ "query": { "script": { "script": { "source": """ def allowed = ['a','b','c']; int invalidCount = 0; for (char c : doc['value'].value.toCharArray()) { if (!allowed.contains(String.valueOf(c))) { invalidCount++; if (invalidCount > 1) return false; } } return invalidCount <= 1; """, "lang": "painless" } } } }
若需支持最多2个非允许字符,只需将脚本中invalidCount > 1和invalidCount <=1改为invalidCount >2和invalidCount <=2即可。
3. 通配符无限次匹配(匹配任意长度非允许内容)
如果需要类似a*c的模式匹配(*表示任意长度内容),可使用wildcard或regexp查询:
Wildcard查询:
{ "query": { "wildcard": { "value": "a*c" } } }
Regexp查询(更灵活):
{ "query": { "regexp": { "value": "a.*c" } } }
性能优化建议
频繁使用此类查询时,建议在索引阶段预计算非允许字符的数量,避免脚本查询的性能损耗:
- 提前定义映射,新增预计算字段:
{ "mappings": { "properties": { "value": {"type": "text"}, "invalid_char_count": {"type": "integer"} } } }
- 索引文档时,提前计算并写入
invalid_char_count值;查询时直接通过范围过滤:
{ "query": { "range": { "invalid_char_count": { "lte": 2 } } } }
内容的提问来源于stack exchange,提问作者xStoryTeller
相关产品推荐
相关产品推荐

