Solr 8.11.1使用DIH索引PDF时软连字符转空格致分词错误如何解决
问题根因
Solr 8.11.1 内置Tika 1.28版本依赖的PDFBox 2.0.25解析组件,对Indesign导出PDF中嵌入的U+00AD软连字符(自由连字符)存在解析bug:非换行位置的软连字符会被直接转换为普通空格(ASCII 0x20),换行位置的软连字符会被输出为可见连字符+换行符。这就是直接在DIH中用正则匹配\u00AD替换为空不生效的原因——软连字符在进入DIH的RegexTransformer逻辑前,已经被底层解析器转成了空格。
不同PDF工具复制文本的结果差异,本质是各工具对软连字符的处理逻辑不统一:Adobe Reader做了专门适配直接移除软连字符,PDF-XChange Viewer和旧版PDFBox逻辑一致将软连字符转成空格,Edge缺少对应字符映射直接输出菱形替换符。
可行解决方案(按落地成本从低到高排序)
方案1:DIH层增加脚本清洗(零依赖修改,优先推荐)
直接在现有DIH配置中增加ScriptTransformer,在Tika输出文本后定向清洗软连字符及其转成的多余空格,不需要替换jar包、不需要改源码。配置示例如下:
<entity name="pdf" processor="TikaEntityProcessor" url="${file.fileAbsolutePath}" format="text" transformer="TemplateTransformer,RegexTransformer,ScriptTransformer"> <!-- 先清理未被转义的残留软连字符 --> <field column="text" regex="\u00AD" replaceWith="" sourceColName="text"/> <!-- 脚本处理被转成空格的软连字符拆分场景 --> <script><![CDATA[ // 可提前将业务常用词加载为Set做校验,避免误合并正常短词,小批量场景可先省略词典校验 var validWords = new java.util.HashSet(); // 此处可加加载外部词典文件的逻辑,全量场景建议配置 function cleanSoftHyphen(row) { var rawText = row.get('text'); if (rawText == null) return row; // 第一步:清除所有残留软连字符 var cleaned = rawText.replace(/\u00AD/g, ''); // 第二步:匹配连续被单个空格分隔的短字母片段(软连字符拆分的词段长度多为1-4个字符) var splitPattern = /(?:\b[a-zA-Z]{1,4}\s){2,}[a-zA-Z]{1,4}\b/g; var matchRes; while ((matchRes = splitPattern.exec(cleaned)) !== null) { var fragment = matchRes[0]; var mergedWord = fragment.replace(/\s/g, ''); // 加词典校验时打开下面注释,无词典可跳过校验直接替换 // if (!validWords.contains(mergedWord.toLowerCase())) continue; cleaned = cleaned.replace(fragment, mergedWord); } row.put('text', cleaned); return row; } ]]></script> <!-- 其他原有field配置保持不变 --> </entity>
该方案上线前先取20份左右问题PDF做小批量验证,调整正则匹配的词段长度阈值,避免把"a pen"、"to do"这类正常短词组合误合并。
方案2:升级内置Tika/PDFBox依赖(一劳永逸)
将Solr部署路径下server/solr-webapp/webapp/WEB-INF/lib/目录内的tika-core、tika-parsers-standard-package、pdfbox、fontbox相关jar包,替换为Tika 1.28.5(对应PDFBox 2.0.29)及以上的兼容版本。
新版本PDFBox已经修复了Indesign导出PDF的软连字符解析bug,软连字符会被正确输出为U+00AD,此时原有直接替换\u00AD为空的RegexTransformer规则即可正常生效,不需要额外写清洗逻辑。
注意:替换核心依赖后必须做全量PDF解析场景的回归测试,避免其他格式PDF的解析逻辑受版本变动影响。
方案3:分词层自定义TokenFilter(不修改原文场景适用)
如果业务要求不能修改存储的原始文本内容,可以实现一个轻量的Solr自定义TokenFilter,挂载到text字段的分析链上:在分词阶段遍历相邻token,若连续多个token都是短字母片段、拼接后命中业务词典,就将这些token合并为一个完整词项输出。
该方案仅在索引和查询的分词阶段做适配,不会改动存储的原始文本,准确率最高,缺点是需要编写少量Java代码打包为自定义jar部署到Solr。
避坑说明
- 不要尝试通过配置Tika的PDFParser参数关闭软连字符转换,Solr 8.11.1的TikaEntityProcessor没有暴露该参数的配置入口,修改无效
- 批量处理前必须做小样本验证,重点检查短文本、列表类内容,避免正常词间空格被误删
- 若使用脚本清洗方案,大数量级场景建议加载业务常用词典做合并校验,误判率可降到0.1%以下
内容的提问来源于stack exchange,提问作者DrugojAndrew

