Lucene.NET 索引文件内容前必须处理编码和文本提取
直接用
File.ReadAllText读取 Word、PDF 或 Excel 文件会得到乱码或二进制垃圾——Lucene.NET 只索引纯文本。你得先抽取出可读内容,再喂给索引器。
常见错误现象:
Document里存的是空字符串、乱码,或者索引后查不到任何结果,但日志没报错。 Office 文档(.docx/.xlsx)推荐用
Apache POI .NET(注意是 .NET 移植版,不是 Java 原版)或
DocX库提取正文 PDF 推荐
PdfPig(轻量、无本地依赖)或
iTextSharp.LGPLv2.Core(注意许可证) 纯文本文件(.txt/.log/.md)才可用
File.ReadAllText(path, Encoding.UTF8),且务必显式指定编码,Windows 默认 ANSI 容易崩 跳过二进制文件(.exe/.dll/.zip):检查
Path.GetExtension(path),不在白名单里就
continue
IndexWriter 配置不匹配会导致索引不可用或崩溃
IndexWriter不是“打开即用”,它的
IndexWriterConfig必须和后续搜索时的
Analyzer对齐,否则分词结果对不上,搜不到东西。
典型错误:
IndexWriter用
StandardAnalyzer,搜索时却用
SimpleAnalyzer,结果所有查询都返回零条。 写入和搜索必须用同一个
Analyzer实例(或至少同类型同配置),推荐封装成静态只读字段,比如
public static readonly Analyzer Analyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48)
LuceneVersion必须统一:C# 版 Lucene.NET 4.8+ 要求明确传
LuceneVersion.LUCENE_48,不能用
null或旧版本常量 别忘了设
config.SetOpenMode(OpenMode.CREATE_OR_APPEND),否则每次重建索引都会清空旧数据 写完必须调
writer.Commit()和
writer.Dispose(),不 commit 就算没写进去;不 Dispose 可能锁住文件夹
Document 字段定义决定能不能搜、搜得准不准
Lucene.NET 不自动推断字段用途,
Field的构造方式直接影响检索行为——搜不到,往往是因为字段没建对。
错误现象:能索引成功,但
QueryParser.Parse("content:hello") 返回空,或者全文搜 "hello"却命中不了。 内容主体字段(如正文)要用
TextField:它会被分词、索引、存储(可选),适合全文检索
new TextField("content", text, Field.Store.YES)
ID 或路径这类唯一标识字段,用 StringField:不分词、精确匹配、可存储
new StringField("path", fullPath, Field.Store.YES)
别用 StoredField存正文——它不索引,只存,搜不到 字段名大小写敏感,
"Content"和
"content"是两个字段,查询时必须完全一致
搜索时 QueryParser 解析规则容易踩坑
QueryParser不是模糊匹配黑盒,它按固定语法解析字符串,写错一个符号就查不到,而且不报错。
常见问题:
QueryParser.Parse("file.pdf") 查不到,但 QueryParser.Parse("path:file.pdf") 可以——因为前者默认查 defaultField,而你没设或设错了。 初始化
QueryParser时,
defaultField参数必须是你索引时用的主文本字段名,比如
"content",不能填
"body"或留空 含空格或特殊字符(
:、
+、
-、
AND)的关键词必须加英文双引号,例如
parser.Parse("\"C# tutorial\"")
想搜带通配符的文件名?WildcardQuery比
QueryParser更可控,
QueryParser的
*和
?只在末尾生效,且性能差 调试时先用
query.ToString()打印实际生成的查询结构,比瞎猜快得多
最麻烦的其实是文件路径权限和并发写入:多个线程共用一个
IndexWriter实例会崩,而每次新建又太慢;同时索引上百个文件时,文本提取耗时远大于 Lucene 写入本身——别把瓶颈误判成 Lucene 问题。
