Apache Lucene 9.5.0:不分词存储下实现大小写不敏感搜索
解决Lucene大小写不敏感搜索问题(保留原字符串存储)
你的问题核心在于**KeywordAnalyzer不会对文本做大小写转换**:索引阶段存储的是原始大小写的John Smith,搜索阶段输入的john smith会被原样处理,导致两者无法匹配。以下是符合你需求的解决方案:
方案:自定义大小写不敏感的KeywordAnalyzer
我们需要一个既能保持不分词特性(和KeywordAnalyzer一致),又能自动处理大小写转换的分析器。可以通过KeywordTokenizer搭配LowerCaseFilter实现:
自定义Analyzer代码
static class CaseInsensitiveKeywordAnalyzer extends Analyzer { @Override protected TokenStreamComponents createComponents(String fieldName) { // 使用KeywordTokenizer保证不分词 Tokenizer tokenizer = new KeywordTokenizer(); // 添加LowerCaseFilter实现大小写统一转换 TokenStream filter = new LowerCaseFilter(tokenizer); return new TokenStreamComponents(tokenizer, filter); } }
修改后的完整示例代码
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.core.KeywordTokenizer; import org.apache.lucene.analysis.core.LowerCaseFilter; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.StringField; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import java.io.IOException; import java.nio.file.Paths; public class LuceneExample { public static void main(String[] args) throws IOException, ParseException { // 使用自定义的大小写不敏感KeywordAnalyzer Analyzer analyzer = new CaseInsensitiveKeywordAnalyzer(); String indexDirectoryPath = "/temp/test"; Directory directory = FSDirectory.open(Paths.get(indexDirectoryPath)); // 索引阶段配置 IndexWriterConfig config = new IndexWriterConfig(analyzer); IndexWriter writer = new IndexWriter(directory, config); Document doc = new Document(); // 保留原始大小写存储 doc.add(new StringField("name", "John Smith", Field.Store.YES)); writer.addDocument(doc); writer.close(); // 搜索阶段配置 IndexReader reader = DirectoryReader.open(directory); IndexSearcher searcher = new IndexSearcher(reader); QueryParser parser = new QueryParser("name", analyzer); // 输入任意大小写的搜索词都能匹配 Query query = parser.parse("john smith"); TopDocs results = searcher.search(query, 10); for (int i = 0; i < results.scoreDocs.length; i++) { Document hitDoc = searcher.doc(results.scoreDocs[i].doc); // 输出原始大小写的字符串:John Smith System.out.println(hitDoc.get("name")); } reader.close(); directory.close(); } static class CaseInsensitiveKeywordAnalyzer extends Analyzer { @Override protected TokenStreamComponents createComponents(String fieldName) { Tokenizer tokenizer = new KeywordTokenizer(); TokenStream filter = new LowerCaseFilter(tokenizer); return new TokenStreamComponents(tokenizer, filter); } } }
关键说明
- 索引逻辑:自定义分析器会将文本转换为小写存入索引,但
StringField的Field.Store.YES会保留原始大小写的字符串,满足你存储需求。 - 搜索逻辑:搜索词会被自动转换为小写,和索引中的小写文本匹配,实现大小写不敏感搜索。
- 一致性要求:索引和搜索必须使用同一个自定义分析器,否则会出现匹配失效问题。
内容的提问来源于stack exchange,提问作者TheHydGuy
相关产品推荐
相关产品推荐

