如何将含数字+单位的文本拆分为三类Token以优化搜索匹配?
刚好之前做过类似的电商商品索引优化,这个问题的核心就是解决数字与单位连写/空格分隔的检索一致性问题,下面给你梳理具体的实现思路和可落地的方案:
核心逻辑
我们需要在常规分词的基础上,额外识别出「数字+单位连写」的token,拆分出独立的数字、单位token,同时保留原连写token,这样不管用户搜74Ah还是74 Ah,都能命中目标文档。
具体实现步骤
1. 先定义精准的正则匹配规则
首先要写出能覆盖绝大多数常见数字+单位组合的正则,既要匹配整数/小数,也要兼容不同格式的单位(大小写、单复数等)。
通用版正则(覆盖大多数场景)
([+-]?\d+\.?\d*)([a-zA-Z]+)
([+-]?\d+\.?\d*):匹配带正负号的整数或小数(比如74、220.5、-12V里的-12)([a-zA-Z]+):匹配后续的字母单位(比如Ah、V、cm)
精准版正则(针对已知单位枚举)
如果你的业务里单位是固定的(比如只涉及电压、长度、电池容量),可以用枚举式正则避免误匹配:
([+-]?\d+\.?\d*)(V|cm|Ah|W|kg|ml|L)
2. 在分词流程中插入自定义处理
不管你用的是开源检索引擎(Elasticsearch/Solr)还是自定义索引系统,都要在常规分词之后加入这个额外处理:
- 先执行常规分词,得到基础token列表(比如
Varta、Super-charge、battery、74Ah) - 遍历每个token,用正则匹配是否为「数字+单位连写」模式
- 匹配成功的话,就把捕获到的数字、单位,以及原连写token(用集合存储避免重复)加入最终token集合
3. 不同场景的落地示例
示例1:Elasticsearch 自定义分词器
在ES里可以通过自定义token_filter来实现,步骤如下:
- 创建包含自定义过滤器的索引设置:
{ "settings": { "analysis": { "filter": { "num_unit_splitter": { "type": "pattern_capture", "preserve_original": true, "patterns": [ "(\\d+\\.?\\d*)([a-zA-Z]+)" ] } }, "analyzer": { "product_search_analyzer": { "tokenizer": "standard", "filter": [ "lowercase", "num_unit_splitter" ] } } } } }
preserve_original: true:保留原连写token(比如74ah)lowercase过滤器:统一转小写,避免大小写检索差异- 测试这个分词器,输入
Varta Super-charge battery 74Ah会得到:varta,super,charge,battery,74ah,74,ah
示例2:Python 自定义索引脚本
如果是自己用Python搭建索引系统,代码可以这样写:
import re def product_tokenizer(text): # 常规分词(实际项目建议用spaCy/nltk等专业分词库) base_tokens = text.split() final_tokens = set(base_tokens) # 用集合自动去重 # 匹配数字+单位的正则 num_unit_pattern = re.compile(r'([+-]?\d+\.?\d*)([a-zA-Z]+)') for token in base_tokens: match = num_unit_pattern.fullmatch(token) if match: num_token = match.group(1) unit_token = match.group(2) final_tokens.add(num_token) final_tokens.add(unit_token.lower()) # 统一转小写优化检索 return list(final_tokens) # 测试 sample_text = "Varta Super-charge battery 74Ah" print(product_tokenizer(sample_text)) # 输出:['Varta', 'Super-charge', 'battery', '74Ah', '74', 'ah']
4. 额外优化建议
- 单位归一化:比如把
AH、Ahs统一转成ah,避免单位格式差异导致的检索失效 - 处理特殊格式:比如带斜线的单位
100km/h,可以调整正则匹配(\d+\.?\d*)([a-zA-Z/]+) - 避免误匹配:如果有类似
abc123def的字符串,不要拆分,所以建议用fullmatch而非search来匹配整个token
内容的提问来源于stack exchange,提问作者Michal Holub
相关产品推荐
相关产品推荐

