16

我刚刚冒险进入看似简单但极其复杂的搜索世界。对于一个应用程序,我需要构建一个搜索机制来通过用户的名字搜索用户。

在阅读了许多帖子和文章后,包括:

如何使用 Lucene 进行个人姓名(名字、姓氏)搜索?
http://dublincore.org/documents/1998/02/03/name-representation/
通过优先考虑用户关系来搜索社交网络的最佳方式是什么?
http://www.gossamer-threads.com/lists/lucene/java-user/120417
Lucene 索引和查询设计问题 - 搜索人员
Lucene 模糊搜索客户名称和部分地址

...以及其他一些我目前找不到的。并且至少在我的机器上进行索引和基本搜索,我为用户搜索设计了以下方案:

1) 具有第一、第二和第三名称字段,并使用 Solr 对它们进行索引
2) 使用 edismax 作为多列搜索的 requestParser
3) 使用归一化过滤器的组合,例如:音译、拉丁语到 ascii 转换等
4 ) 最后使用模糊搜索

显然,我对此非常陌生,我不确定上述方法是否是最好的方法,并且希望听到有经验的用户在这个领域比我有更好的想法。

我需要能够通过以下方式匹配名称:

1) 重音折叠:Jorn 匹配 Jörn,反之亦然
2) 替代拼写:Karl 匹配 Carl,反之亦然
3) 缩短表示(我相信我使用 SynonymFilterFactory 这样做):Sue 匹配 Susanne 等
4) Levenstein 匹配:Jonn 匹配John 等
5) Soundex 匹配:Elin 和 Ellen

非常欢迎任何指导、批评或评论。请让我知道这是否可能……或者我只是在做白日梦。:)


编辑

我还必须补充一点,我还有一个全名字段,以防某些人的名字很长,例如其中一篇文章:Jon Paul 或 Del Carmen 也应该匹配 Jon Paul Del Carmen

由于这是一个新项目,我可以以任何我认为合适的方式修改架构和架构,因此限制非常有限。

4

5 回答 5

9

听起来您正在为需要非常松散匹配的搜索来满足语料库的需求?

如果您这样做,您将需要选择您的字段并设置不同的提升来对您的结果进行排名。

所以在 solr 中有单独的“复制”字段:

  • 一个字段的确切全名(带过滤器)
  • 带有过滤器的多值字段 ASCIIFolding、小写...
  • 具有 SynonymFilterFactory ASCIIFolding、Lowercase... 的多值字段
  • PhoneticFilterFactory(带有CaverphoneDouble-Metaphone

另请参阅:更多非英语 Soundex 讨论

名称的同义词,我不知道是否有可用的公共同义词 db。

模糊搜索,我没有发现它有用,它使用 Levenshtein 距离。

其他过滤器和索引可以获得更出色的“搜索相关”结果。

可以使用ASCIIFoldingFilterFactory处理名称中的 Unicode 字符

您正在为预期的用例预先描述解决方案。

如果您想要高质量的结果,请计划调整您的搜索相关性

当尝试匹配同义词时,这种调整将特别有价值,例如 MacDonald 和 McDonald(其 Levenshtein 距离比 Carl 和 Karl 大)。

于 2011-04-05T12:40:26.507 回答
3

找到一个昵称db,不知道好不好: http ://www.peacockdata2.com/products/pdnickname/

请注意,它不是免费的。

于 2012-09-20T07:37:31.493 回答
1

另一个帖子中的答案还不错: Training solr to identifynicknames or name variant

<fieldType name="name_en" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">
  <analyzer type="index">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.ASCIIFoldingFilterFactory"/>
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.ASCIIFoldingFilterFactory"/>
    <filter class="solr.SynonymFilterFactory" synonyms="english_names.txt" ignoreCase="true" expand="true"/>
  </analyzer>
</fieldType>
于 2016-03-03T06:17:20.043 回答
1

对于拼音名称搜索,您还可以尝试使用Beider-Morse 过滤器,如果您有来自不同国家/地区的混合名称,它会非常有效。

如果您想将其与预先输入功能一起使用,请将其与 EdgeNGramFilter 结合使用:

<fieldType name="phoneticNames" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">
  <analyzer type="index">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.BeiderMorseFilterFactory" nameType="GENERIC" ruleType="APPROX" concat="true" languageSet="auto"/>
    <filter class="solr.EdgeNGramFilterFactory" minGramSize="3" maxGramSize="15"/>
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.BeiderMorseFilterFactory" nameType="GENERIC" ruleType="APPROX" concat="true" languageSet="auto"/>
  </analyzer>
</fieldType>
于 2016-04-07T14:32:20.310 回答
0

我们创建了一个简单的“名称”字段类型,它允许混合上述答案的“键”(例如,SOUNDEX)和“成对”部分。

这是概述:

  1. 在索引时,自定义类型的字段被索引到一组(子)字段中,其各自的值用于匹配不同种类的变体的高召回率

这是其实现的核心......

List<IndexableField> createFields(SchemaField field, String name) {
        Collection<FieldSpec> nameFields = deriveFieldsForName(name);
        List<IndexableField> docFields = new ArrayList<>();
        for (FieldSpec fs : nameFields) {
            docFields.add(new Field(fs.getName(), fs.getStringValue(),
                         fs.getLuceneField()));
        }
        docFields.add(createDocValues(field.getName(), new Name(name)));
        return docFields;
}

其核心是deriveFieldsForName(name),您可以在其中包含来自PhoneticFilters、LowerCaseFolding 等的“键”。

  1. 在查询时,首先会生成一个自定义 Lucene 查询,该查询已针对召回进行了调整,并且使用与索引时间相同的字段

这是其实现的核心......

public Query getFieldQuery(QParser parser, SchemaField field, String val) {
        Name name = parseNameString(externalVal, parser.getParams());
        QuerySpec querySpec = buildQuery(name);
        return querySpec.accept(new SolrQueryVisitor(field.getName())); 
}

其核心是 buildQuery(name) 方法,它应该生成一个知道上面的 derivedFieldsForName(name) 的查询,因此对于给定的查询名称,它将找到好的候选名称。

  1. 然后其次,使用 Solr 的 Rerank 功能应用高精度的重新评分算法对结果进行重新排序

这是您的查询中的内容...

&rq={!myRerank reRankQuery=$rrq} &rrq={!func}myMatch(fieldName, "John Doe")

myMatch 的内容可以具有成对的 Levenstein 或 Jaro-Winkler 实现。

注意:我们自己的完整实现使用了私有代码的 derivedFieldsForName、buildQuery 和 myMatch(请参阅http://www.basistech.com/text-analytics/rosette/name-indexer/)来处理上面提到的更多种类的变体(例如,缺少空格、跨语言)。

于 2015-03-23T17:52:28.157 回答