我想使用 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”的阿拉伯联合酋长国相关地址。

还有 设置允许前导通配符

但要 小心. 。这可能会导致性能非常昂贵(这就是默认情况下禁用它的原因)。也许在某些情况下这将是一个简单的解决方案,但我更喜欢自定义标记器,如 犹大·希曼戈, , 也。

您可以使用一个单独的字段来索引反转的电子邮件地址:索引'foo@gmail.com'为'moc.liamg@oof',它使您可以查询“ moc.liamg@*”

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top