Solr模糊搜索编辑距离大于1时无法匹配目标文档问题排查
环境信息
- Java版本:
11.0.122021-07-20 LTS - Solr版本:
8.9.0
Solr配置详情
索引字段配置
<field name="Field1" type="string" multiValued="false" indexed="false" stored="true"/> <field name="author" type="text_general" multiValued="false" indexed="true" stored="true"/> <field name="Field2" type="string" multiValued="false" indexed="false" stored="true"/>
字段类型配置
<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100" multiValued="true"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType>
操作与问题现象
- 执行命令创建Core:
./solr create -c fuzzyCore,通过CSV文件导入数据。 - 执行组合查询:
返回12条Field1为curl "http://localhost:8983/solr/fuzzyCore/select" --data-urlencode "q=author:beaeb~' AND Field1:(w1 x)" --data-urlencode "rows=20"x的文档,但未匹配到Field1为w1、author为bebbeb的目标文档。 - 单独查询
Field1:w1:
可以正常找到目标文档。curl "http://localhost:8983/solr/fuzzyCore/select" --data-urlencode "q=Field1:w1" - 执行模糊查询+Field1组合:
返回0条结果。curl "http://localhost:8983/solr/fuzzyCore/select" --data-urlencode "q=author:beaeb~' AND Field1:w1"
原因解析
1. 查询语句存在语法错误
你写的author:beaeb~'里多了一个额外的单引号,这个单引号会被Solr解析为查询字符串的一部分,实际查询的是beaeb~'这个完整token,而目标文档的author字段是bebbeb,自然无法匹配。
2. 模糊搜索的默认编辑距离限制
即使去掉单引号,默认情况下beaeb~也匹配不到bebbeb,原因在于Lucene模糊搜索的默认规则:
- 当不指定编辑距离参数时,系统会根据查询字符串的长度自动限制允许的最大编辑次数:
- 字符串长度1-2:仅允许完全匹配(编辑距离0)
- 长度3-5:允许最多1次编辑
- 长度≥6:允许最多2次编辑
beaeb是5个字符,默认允许的编辑距离是1;而beaeb到bebbeb的Levenshtein编辑距离是2(比如插入一个字符+替换一个字符),超过了默认限制,所以匹配失败。
3. 分词器的误解
你提到使用StandardTokenizer支持单字搜索,但这个分词器只会按空格、标点等分隔符拆分文本,不会把连续的字母字符串(比如bebbeb)拆分成单个字符的token。它会把整个bebbeb当成一个完整的token,模糊搜索是针对这个完整token计算编辑距离,而非单字。
解决办法
- 修正查询语句的语法错误,去掉多余的单引号,并手动指定编辑距离为2:
curl "http://localhost:8983/solr/fuzzyCore/select" --data-urlencode "q=author:beaeb~2 AND Field1:w1" --data-urlencode "rows=20" - 如果确实需要单字级别的模糊搜索,需要修改
text_general字段类型的分词配置,比如使用KeywordTokenizerFactory配合NGramFilterFactory,将连续字符串拆分为单个字符或指定长度的子串,示例配置:
然后将<fieldType name="text_ngram" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="solr.KeywordTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="1"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.KeywordTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="1"/> </analyzer> </fieldType>author字段的类型改为text_ngram,即可支持单字的模糊匹配。
内容的提问来源于stack exchange,提问作者user595014
相关产品推荐
相关产品推荐

