Solr配置ShingleFilter后带空格查询无法匹配连写词问题求解
问题根因
出现这个匹配差异的核心原因有两点:
- 分词规则不统一:当前使用的
StandardTokenizerFactory对输入的拆分逻辑是按空格/标点切分:连写的WashingMachine没有空格,会被识别为单个词元;带空格的Washing machine会被拆成Washing、Machine两个独立词元。默认无参数配置的ShingleFilterFactory拼接相邻词元时用空格做分隔符,生成的组合词元是washing machine(带空格),和连写的washingmachine编辑距离仅为1,所以单term模糊查询(WashingMachine~默认编辑距离为2)可以通过模糊规则命中带空格的文档。 - 查询语义偏差:带空格的查询词用单引号包裹后属于短语查询,末尾的
~代表短语斜率(slop,即允许的词元位置偏移量),不是单term的编辑距离模糊。短语查询要求文档必须包含查询拆分出的所有独立词元,且位置差符合slop要求。但连写的WashingMachine在索引里只有单个词元,根本没有washing、machine两个独立词元,自然无法被匹配。
解决方案
方案1:调整分词配置(推荐,长期生效)
通过配置让带空格词组和连写组合词在索引、查询阶段生成完全一致的词元集合,从根源消除匹配差异,不需要业务侧做特殊处理。
- 修改managed-schema中的
text_general字段类型配置:在StandardTokenizerFactory后新增WordDelimiterGraphFilterFactory,用来自动拆分驼峰/无分隔符的连写词,同时保留原词、拼接词;调整ShingleFilterFactory参数,保留单个词元、将拼接分隔符设为空,避免生成带空格的组合词元。
修改后的完整配置参考:
<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100" multiValued="true"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> <!-- 新增:处理连写、驼峰词拆分 --> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1" preserveOriginal="1"/> <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/> <filter class="solr.LowerCaseFilterFactory"/> <!-- 调整Shingle配置:保留单个词元,拼接时去掉空格分隔 --> <filter class="solr.ShingleFilterFactory" minShingleSize="2" maxShingleSize="2" outputUnigrams="true" tokenSeparator=""/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> <!-- 和索引阶段保持一致的连写词处理配置 --> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1" preserveOriginal="1"/> <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/> <filter class="solr.SynonymGraphFilterFactory" expand="true" ignoreCase="true" synonyms="synonyms.txt"/> <filter class="solr.LowerCaseFilterFactory"/> <!-- 和索引阶段保持一致的Shingle配置 --> <filter class="solr.ShingleFilterFactory" minShingleSize="2" maxShingleSize="2" outputUnigrams="true" tokenSeparator=""/> </analyzer> </fieldType>
- 配置保存后,需要对对应SolrCore执行全量索引重导,存量数据会按照新的分词规则重新生成词元,配置才能生效。
配置生效后,无论输入是带空格的"Washing Machine"还是连写的"WashingMachine",都会生成washing、machine、washingmachine三个词元,所有查询场景下都能同时命中两条文档。可以通过Solr后台的Analysis页面验证词元生成结果,确认两类输入的词元输出一致后再上线业务查询。
方案2:调整查询语句(无需改配置,临时生效)
如果暂时不能修改schema、重导索引,可以直接调整查询写法,放弃纯短语查询,手动增加去空格后的连写词模糊匹配条件,覆盖连写场景。
将原查询命令:
curl -G http://localhost:8983/solr/solrCore/select --data-urlencode "q=(ProductName:'Washing Machine~')"
修改为:
curl -G http://localhost:8983/solr/solrCore/select --data-urlencode "q=(ProductName:(Washing Machine~) OR ProductName:(WashingMachine~))"
该写法会同时匹配包含washing、machine模糊命中的文档,以及washingmachine模糊命中的文档,不需要改分词配置即可返回两条结果。缺点是需要业务侧对用户输入做预处理,手动去除空格生成连写词加入查询条件,通用性差,仅适合临时使用。
内容的提问来源于stack exchange,提问作者user752590
相关产品推荐
相关产品推荐

