我想使用 Lucene(特别是 Lucene.NET)来搜索电子邮件地址域。
例如,我想搜索“@gmail.com”以查找发送到 gmail 地址的所有电子邮件。
对“*@gmail.com”运行 Lucene 查询会导致错误,星号不能位于查询的开头。对“@gmail.com”运行查询不会返回任何匹配项,因为“foo@gmail.com”被视为一个完整的单词,您不能只搜索单词的一部分。
我怎样才能做到这一点?
没有人给出令人满意的答案,因此我们开始研究 Lucene 文档,发现我们可以使用自定义分析器和标记器来完成此任务。
答案是这样的:创建一个 WhitespaceAndAtSymbolTokenizer 和一个 WhitespaceAndAtSymbolAnalyzer,然后使用这个分析器重新创建索引。执行此操作后,搜索“@gmail.com”将返回所有 gmail 地址,因为由于我们刚刚创建的 Tokenizer,它被视为一个单独的词。
这是源代码,它实际上非常简单:
class WhitespaceAndAtSymbolTokenizer : CharTokenizer
{
public WhitespaceAndAtSymbolTokenizer(TextReader input)
: base(input)
{
}
protected override bool IsTokenChar(char c)
{
// Make whitespace characters and the @ symbol be indicators of new words.
return !(char.IsWhiteSpace(c) || c == '@');
}
}
internal class WhitespaceAndAtSymbolAnalyzer : Analyzer
{
public override TokenStream TokenStream(string fieldName, TextReader reader)
{
return new WhitespaceAndAtSymbolTokenizer(reader);
}
}
就是这样!现在您只需要重建索引并使用这个新的分析器进行所有搜索。例如,要将文档写入索引:
IndexWriter index = new IndexWriter(indexDirectory, new WhitespaceAndAtSymbolAnalyzer());
index.AddDocument(myDocument);
执行搜索也应该使用分析器:
IndexSearcher searcher = new IndexSearcher(indexDirectory);
Query query = new QueryParser("TheFieldNameToSearch", new WhitespaceAndAtSymbolAnalyzer()).Parse("@gmail.com");
Hits hits = query.Search(query);
我看到你有你的解决方案,但我的会避免这种情况,并在你正在索引的文档中添加一个名为 email_domain 的字段,我会在其中添加电子邮件地址的解析域。这听起来可能很愚蠢,但与此相关的存储量非常少。如果您想变得更高级,假设某个域有很多子域,则可以改为创建一个域,将反向域放入其中,这样您就可以存储 com.gmail、com.company.department 或 ae.eim,这样您就可以找到所有带有“ae”前缀查询的阿拉伯联合酋长国相关地址。
But be careful. This could get very performance expensive (thats why it is disabled by default). Maybe in some cases this would be an easy solution, but I would prefer a custom Tokenizer as stated by Judah Himango, too.
您可以使用一个单独的字段来索引反向的电子邮件地址: Index 'foo@gmail.com' as 'moc.liamg@oof' 这使您可以查询“moc.liamg@*”