如何使用Lucene拆分特殊字符并为每个特殊字符建立索引及实例求助
嘿,我来帮你搞定这两个Lucene令牌处理的问题!
1. 如何拆分特殊字符并为每个特殊字符建立索引
要实现把特殊字符单独拆分并索引,核心是选对分词器(Tokenizer)——Lucene默认的分词器(比如StandardTokenizer)会把很多特殊字符当作分隔符或者直接忽略,所以得针对性配置。这里有两种常用方案:
方案A:拆分所有字符(包括字母数字)
如果需要把每一个字符都单独作为令牌(比如把abc!拆成a,b,c,!),可以用PatternTokenizer搭配匹配单个字符的正则表达式:
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.pattern.PatternTokenizer; import java.util.regex.Pattern; public class CharSplitAnalyzer extends Analyzer { // 正则表达式匹配任意单个字符 private static final Pattern CHAR_PATTERN = Pattern.compile("."); @Override protected TokenStreamComponents createComponents(String fieldName) { // 用PatternTokenizer拆分每个字符 Tokenizer tokenizer = new PatternTokenizer(CHAR_PATTERN, 0); return new TokenStreamComponents(tokenizer); } }
方案B:拆分特殊字符,保留连续字母数字为单个令牌
如果只想把特殊字符单独拆分,而连续的字母数字(比如debug)保留为一个令牌,可以用PatternTokenizer搭配区分特殊字符和字母数字的正则:
// 正则匹配:非字母数字字符(单独成令牌) 或 连续字母数字(成一个令牌) private static final Pattern SPLIT_PATTERN = Pattern.compile("([^\\w]|\\w+)");
这样就能把test@123拆成test,@,123,每个特殊字符都被单独索引。
2. 拆分$("#debug_threads")为指定令牌的解决方案
你提到用Token Filter没成功,大概率是因为默认Tokenizer没有把这些特殊字符和下划线提前拆分出来。这里给你两种靠谱的实现方式:
方式1:用PatternTokenizer直接精准拆分
这种方式一步到位,用正则表达式匹配你需要的所有令牌类型:
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.pattern.PatternTokenizer; import java.util.regex.Pattern; public class CustomDebugAnalyzer extends Analyzer { // 正则匹配:非字母数字字符 | 下划线 | 连续字母数字 private static final Pattern DEBUG_SPLIT_PATTERN = Pattern.compile("([^\\w]|_|\\w+)"); @Override protected TokenStreamComponents createComponents(String fieldName) { // 取正则的第一个分组作为令牌内容 Tokenizer tokenizer = new PatternTokenizer(DEBUG_SPLIT_PATTERN, 1); return new TokenStreamComponents(tokenizer); } }
测试这个分析器,输入$("#debug_threads"),会得到你想要的令牌序列:$, (, ", #, debug, _, threads, ", )。
方式2:StandardTokenizer + WordDelimiterFilter组合
如果更倾向于用标准分词器搭配Filter,可以用StandardTokenizer先拆分大部分特殊字符,再用WordDelimiterFilter把下划线从字母序列中拆分出来:
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.core.StandardTokenizer; import org.apache.lucene.analysis.miscellaneous.WordDelimiterFilter; public class DebugAnalyzerWithFilter extends Analyzer { @Override protected TokenStreamComponents createComponents(String fieldName) { Tokenizer tokenizer = new StandardTokenizer(); // 开启"按下划线拆分"的配置 WordDelimiterFilter filter = new WordDelimiterFilter( tokenizer, WordDelimiterFilter.SPLIT_ON_UNDERSCORE, null ); return new TokenStreamComponents(tokenizer, filter); } }
StandardTokenizer会先把$("#debug_threads")拆成$, (, ", #, debug_threads, ", ),然后WordDelimiterFilter会把debug_threads拆成debug, _, threads,最终得到你需要的所有令牌。
内容的提问来源于stack exchange,提问作者Deepak Srinivasan




