使用Lucene搜索电子邮件地址
我想使用Lucene(尤其是Lucene.NET)搜索电子邮件地址域。
例如。我想搜索" @ gmail.com"以查找发送到gmail地址的所有电子邮件。
对" *@gmail.com"运行Lucene查询会导致错误,星号不能出现在查询的开头。对" @ gmail.com"运行查询不会返回任何匹配项,因为" [email protected]"被视为一个完整的单词,我们不能仅搜索单词的一部分。
我怎样才能做到这一点?
解决方案
回答
没有人给出满意的答案,因此我们开始浏览Lucene文档,发现可以使用自定义分析器和Tokenizer实现此目的。
答案是这样的:创建一个WhitespaceAndAtSymbolTokenizer和WhitespaceAndAtSymbolAnalyzer,然后使用此分析器重新创建索引。完成此操作后,搜索" @ gmail.com"将返回所有gmail地址,因为我们刚刚创建的令牌生成器将其视为一个单独的单词。
这是源代码,它实际上非常简单:
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); } }
而已!现在,我们只需要重建索引并使用此新的Analyzer进行所有搜索。例如,将文档写入索引:
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"。
回答
我们可以使用一个单独的字段来索引反向的电子邮件地址:
将'[email protected]'索引为'moc.liamg@oof'
这使我们可以查询" moc.liamg@*"
回答
还有setAllowLeadingWildcard
不过要小心。这可能会使性能变得非常昂贵(这就是为什么默认情况下禁用它的原因)。也许在某些情况下这将是一个简单的解决方案,但我也希望像Judah Himango所说的那样使用自定义标记器。