如何在Solr中实现电话号码类同义词的过滤与分词?
问题描述
我需要Solr支持搜索存储格式为+79876543210的电话号码,同时兼容以下多种查询格式:
+79876543210 79876543210 89876543210 <-- '+7'替换为地区码'8' 9876543210 <-- 完全移除'+7'
固定电话场景同样需要兼容多种变体:
+78662123456 <-- '+78662'为特定地区码 78662123456 88662123456 8662123456 123456 <-- 完全移除地区码
之前试过单独存储号码变体用于搜索,但高亮时会返回<em>123456</em>,而实际展示给用户的是原始号码+78662123456,体验很差。想用managed synonyms但官方文档明确说:
通过REST API对托管资源所做的更改,需重载Solr集合(单服务器模式下为core)后才会应用到活动组件。
每次加数据都重载core不现实,还会有同步问题,求其他Solr原生解决方案。
解决方案
核心思路是用Solr的字符/令牌过滤器,在索引和查询阶段自动将所有号码变体转换成统一的匹配规则,同时保留原始号码用于展示和高亮,全程不需要维护额外同义词或重载core。
1. 定义专用电话号码字段类型
在managed-schema(或旧版schema.xml)中添加针对电话号码的字段类型,通过分析器处理所有变体:
<fieldType name="phone_number" class="solr.TextField" positionIncrementGap="100"> <!-- 索引阶段:生成所有可能的匹配令牌 --> <analyzer type="index"> <!-- 第一步:移除所有非数字字符,只保留纯数字 --> <charFilter class="solr.PatternReplaceCharFilterFactory" pattern="[^0-9]" replacement=""/> <!-- 把整个号码作为单个令牌 --> <tokenizer class="solr.KeywordTokenizerFactory"/> <!-- 生成令牌1:替换开头的7为8(匹配用户输入8开头的号码) --> <filter class="solr.PatternReplaceTokenFilterFactory" pattern="^7" replacement="8" preserveOriginal="true"/> <!-- 生成令牌2:去掉开头的7(匹配用户输入不带国家码的号码) --> <filter class="solr.PatternReplaceTokenFilterFactory" pattern="^7" replacement="" preserveOriginal="true"/> <!-- 生成令牌3:提取最后6位数字(匹配用户输入仅本地号码的场景) --> <filter class="solr.PatternReplaceTokenFilterFactory" pattern=".*(\d{6})$" replacement="$1" preserveOriginal="false"/> </analyzer> <!-- 查询阶段:将用户输入转换成可匹配的令牌 --> <analyzer type="query"> <!-- 同样先移除非数字字符 --> <charFilter class="solr.PatternReplaceCharFilterFactory" pattern="[^0-9]" replacement=""/> <tokenizer class="solr.KeywordTokenizerFactory"/> <!-- 把输入的8开头号码转换成7开头,同时保留原始8开头令牌 --> <filter class="solr.PatternReplaceTokenFilterFactory" pattern="^8" replacement="7" preserveOriginal="true"/> </analyzer> </fieldType>
分析器逻辑说明
- 索引时:原始号码
+79876543210会被转换成3个令牌:79876543210、89876543210、9876543210;固定电话+78662123456会生成78662123456、88662123456、8662123456、123456。 - 查询时:用户输入的任何格式都会被转换成对应令牌,比如输入
123456直接匹配索引时的最后6位令牌,输入89876543210会生成89876543210和79876543210两个令牌,同时匹配索引中的对应项。
2. 配置字段
添加一个字段,同时存储原始号码并应用上面的分析器:
<field name="phone" type="phone_number" stored="true" indexed="true"/>
stored="true":保留原始号码用于展示和高亮indexed="true":用上面的分析器生成索引令牌
3. 高亮配置
查询时只需开启高亮并指定phone字段即可:
hl=true&hl.fl=phone&hl.usePhraseHighlighter=true
因为字段存储的是原始号码,Solr会自动在原始号码上高亮匹配的部分,比如用户搜索123456,返回的高亮结果会正确指向原始号码的对应片段。
额外优化
如果需要区分手机号和固定电话的规则,可以定义两个不同的字段类型,分别调整过滤器的正则规则(比如手机号保留最后10位,固定电话保留最后6位)。
内容的提问来源于stack exchange,提问作者Kasbolat Kumakhov
相关产品推荐
相关产品推荐

